648540858
4 years ago
committed by
GitHub
36 changed files with 3260 additions and 249 deletions
@ -0,0 +1,18 @@ |
|||
package com.genersoft.iot.vmp.conf; |
|||
|
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
@Configuration("userSetup") |
|||
public class UserSetup { |
|||
@Value("${userSettings.savePositionHistory}") |
|||
boolean savePositionHistory; |
|||
|
|||
public boolean getSavePositionHistory() { |
|||
return savePositionHistory; |
|||
} |
|||
|
|||
public void setSavePositionHistory(boolean savePositionHistory) { |
|||
this.savePositionHistory = savePositionHistory; |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.genersoft.iot.vmp.gb28181.bean; |
|||
|
|||
public class BaiduPoint { |
|||
|
|||
String bdLng; |
|||
|
|||
String bdLat; |
|||
|
|||
public String getBdLng() { |
|||
return bdLng; |
|||
} |
|||
|
|||
public void setBdLng(String bdLng) { |
|||
this.bdLng = bdLng; |
|||
} |
|||
|
|||
public String getBdLat() { |
|||
return bdLat; |
|||
} |
|||
|
|||
public void setBdLat(String bdLat) { |
|||
this.bdLat = bdLat; |
|||
} |
|||
} |
@ -0,0 +1,166 @@ |
|||
package com.genersoft.iot.vmp.gb28181.bean; |
|||
|
|||
/** |
|||
* @Description: 移动位置bean |
|||
* @author: lawrencehj |
|||
* @date: 2021年1月23日 |
|||
*/ |
|||
|
|||
public class MobilePosition { |
|||
/** |
|||
* 设备Id |
|||
*/ |
|||
private String deviceId; |
|||
|
|||
/** |
|||
* 设备名称 |
|||
*/ |
|||
private String deviceName; |
|||
|
|||
/** |
|||
* 通知时间 |
|||
*/ |
|||
private String time; |
|||
|
|||
/** |
|||
* 经度 |
|||
*/ |
|||
private double longitude; |
|||
|
|||
/** |
|||
* 纬度 |
|||
*/ |
|||
private double latitude; |
|||
|
|||
/** |
|||
* 海拔高度 |
|||
*/ |
|||
private double altitude; |
|||
|
|||
/** |
|||
* 速度 |
|||
*/ |
|||
private double speed; |
|||
|
|||
/** |
|||
* 方向 |
|||
*/ |
|||
private double direction; |
|||
|
|||
/** |
|||
* 位置信息上报来源(Mobile Position、GPS Alarm) |
|||
*/ |
|||
private String reportSource; |
|||
|
|||
/** |
|||
* 国内地理坐标系(GCJ-02 / BD-09) |
|||
*/ |
|||
private String GeodeticSystem; |
|||
|
|||
/** |
|||
* 国内坐标系:经度坐标 |
|||
*/ |
|||
private String cnLng; |
|||
|
|||
/** |
|||
* 国内坐标系:纬度坐标 |
|||
*/ |
|||
private String cnLat; |
|||
|
|||
|
|||
public String getDeviceId() { |
|||
return deviceId; |
|||
} |
|||
|
|||
public void setDeviceId(String deviceId) { |
|||
this.deviceId = deviceId; |
|||
} |
|||
|
|||
public String getDeviceName() { |
|||
return deviceName; |
|||
} |
|||
|
|||
public void setDeviceName(String deviceName) { |
|||
this.deviceName = deviceName; |
|||
} |
|||
|
|||
public String getTime() { |
|||
return time; |
|||
} |
|||
|
|||
public void setTime(String time) { |
|||
this.time = time; |
|||
} |
|||
|
|||
public double getLongitude() { |
|||
return longitude; |
|||
} |
|||
|
|||
public void setLongitude(double longitude) { |
|||
this.longitude = longitude; |
|||
} |
|||
|
|||
public double getLatitude() { |
|||
return latitude; |
|||
} |
|||
|
|||
public void setLatitude(double latitude) { |
|||
this.latitude = latitude; |
|||
} |
|||
|
|||
public double getAltitude() { |
|||
return altitude; |
|||
} |
|||
|
|||
public void setAltitude(double altitude) { |
|||
this.altitude = altitude; |
|||
} |
|||
|
|||
public double getSpeed() { |
|||
return speed; |
|||
} |
|||
|
|||
public void setSpeed(double speed) { |
|||
this.speed = speed; |
|||
} |
|||
|
|||
public double getDirection() { |
|||
return direction; |
|||
} |
|||
|
|||
public void setDirection(double direction) { |
|||
this.direction = direction; |
|||
} |
|||
|
|||
public String getReportSource() { |
|||
return reportSource; |
|||
} |
|||
|
|||
public void setReportSource(String reportSource) { |
|||
this.reportSource = reportSource; |
|||
} |
|||
|
|||
public String getGeodeticSystem() { |
|||
return GeodeticSystem; |
|||
} |
|||
|
|||
public void setGeodeticSystem(String geodeticSystem) { |
|||
GeodeticSystem = geodeticSystem; |
|||
} |
|||
|
|||
public String getCnLng() { |
|||
return cnLng; |
|||
} |
|||
|
|||
public void setCnLng(String cnLng) { |
|||
this.cnLng = cnLng; |
|||
} |
|||
|
|||
public String getCnLat() { |
|||
return cnLat; |
|||
} |
|||
|
|||
public void setCnLat(String cnLat) { |
|||
this.cnLat = cnLat; |
|||
} |
|||
} |
@ -0,0 +1,385 @@ |
|||
package com.genersoft.iot.vmp.gb28181.transmit.request.impl; |
|||
|
|||
import java.io.ByteArrayInputStream; |
|||
import java.text.ParseException; |
|||
import java.util.Iterator; |
|||
|
|||
import javax.sip.InvalidArgumentException; |
|||
import javax.sip.RequestEvent; |
|||
import javax.sip.SipException; |
|||
import javax.sip.message.Request; |
|||
import javax.sip.message.Response; |
|||
|
|||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
|||
import com.genersoft.iot.vmp.conf.UserSetup; |
|||
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint; |
|||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|||
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; |
|||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
|||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
|||
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; |
|||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; |
|||
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
|||
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
|||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
|||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|||
import com.genersoft.iot.vmp.utils.GpsUtil; |
|||
import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
|||
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
|||
|
|||
import org.dom4j.Document; |
|||
import org.dom4j.DocumentException; |
|||
import org.dom4j.Element; |
|||
import org.dom4j.io.SAXReader; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
/** |
|||
* @Description: Notify请求处理器 |
|||
* @author: lawrencehj |
|||
* @date: 2021年1月27日 |
|||
*/ |
|||
|
|||
public class NotifyRequestProcessor extends SIPRequestAbstractProcessor { |
|||
|
|||
private UserSetup userSetup = (UserSetup) SpringBeanFactory.getBean("userSetup"); |
|||
|
|||
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); |
|||
|
|||
private SIPCommander cmder; |
|||
|
|||
private IVideoManagerStorager storager; |
|||
|
|||
private IRedisCatchStorage redisCatchStorage; |
|||
|
|||
private EventPublisher publisher; |
|||
|
|||
private RedisUtil redis; |
|||
|
|||
private DeferredResultHolder deferredResultHolder; |
|||
|
|||
private DeviceOffLineDetector offLineDetector; |
|||
|
|||
private static final String NOTIFY_CATALOG = "Catalog"; |
|||
private static final String NOTIFY_ALARM = "Alarm"; |
|||
private static final String NOTIFY_MOBILE_POSITION = "MobilePosition"; |
|||
|
|||
@Override |
|||
public void process(RequestEvent evt) { |
|||
try { |
|||
Element rootElement = getRootElement(evt); |
|||
String cmd = XmlUtil.getText(rootElement, "CmdType"); |
|||
|
|||
if (NOTIFY_CATALOG.equals(cmd)) { |
|||
logger.info("接收到Catalog通知"); |
|||
processNotifyCatalogList(evt); |
|||
} else if (NOTIFY_ALARM.equals(cmd)) { |
|||
logger.info("接收到Alarm通知"); |
|||
processNotifyAlarm(evt); |
|||
} else if (NOTIFY_MOBILE_POSITION.equals(cmd)) { |
|||
logger.info("接收到MobilePosition通知"); |
|||
processNotifyMobilePosition(evt); |
|||
} else { |
|||
logger.info("接收到消息:" + cmd); |
|||
response200Ok(evt); |
|||
} |
|||
} catch (DocumentException | SipException |InvalidArgumentException | ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 处理MobilePosition移动位置Notify |
|||
* @param evt |
|||
*/ |
|||
private void processNotifyMobilePosition(RequestEvent evt) { |
|||
try { |
|||
//回复 200 OK
|
|||
Element rootElement = getRootElement(evt); |
|||
MobilePosition mobilePosition = new MobilePosition(); |
|||
Element deviceIdElement = rootElement.element("DeviceID"); |
|||
String deviceId = deviceIdElement.getTextTrim().toString(); |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
if (device != null) { |
|||
if (!StringUtils.isEmpty(device.getName())) { |
|||
mobilePosition.setDeviceName(device.getName()); |
|||
} |
|||
} |
|||
mobilePosition.setDeviceId(XmlUtil.getText(rootElement, "DeviceID")); |
|||
mobilePosition.setTime(XmlUtil.getText(rootElement, "Time")); |
|||
mobilePosition.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude"))); |
|||
mobilePosition.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude"))); |
|||
if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Speed"))) { |
|||
mobilePosition.setSpeed(Double.parseDouble(XmlUtil.getText(rootElement, "Speed"))); |
|||
} else { |
|||
mobilePosition.setSpeed(0.0); |
|||
} |
|||
if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Direction"))) { |
|||
mobilePosition.setDirection(Double.parseDouble(XmlUtil.getText(rootElement, "Direction"))); |
|||
} else { |
|||
mobilePosition.setDirection(0.0); |
|||
} |
|||
if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Altitude"))) { |
|||
mobilePosition.setAltitude(Double.parseDouble(XmlUtil.getText(rootElement, "Altitude"))); |
|||
} else { |
|||
mobilePosition.setAltitude(0.0); |
|||
} |
|||
mobilePosition.setReportSource("Mobile Position"); |
|||
BaiduPoint bp = new BaiduPoint(); |
|||
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); |
|||
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); |
|||
mobilePosition.setGeodeticSystem("BD-09"); |
|||
mobilePosition.setCnLng(bp.getBdLng()); |
|||
mobilePosition.setCnLat(bp.getBdLat()); |
|||
if (!userSetup.getSavePositionHistory()) { |
|||
storager.clearMobilePositionsByDeviceId(deviceId); |
|||
} |
|||
storager.insertMobilePosition(mobilePosition); |
|||
response200Ok(evt); |
|||
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
/*** |
|||
* 处理alarm设备报警Notify |
|||
* @param evt |
|||
*/ |
|||
private void processNotifyAlarm(RequestEvent evt) { |
|||
try { |
|||
Element rootElement = getRootElement(evt); |
|||
Element deviceIdElement = rootElement.element("DeviceID"); |
|||
String deviceId = deviceIdElement.getText().toString(); |
|||
|
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
if (device == null) { |
|||
return; |
|||
} |
|||
DeviceAlarm deviceAlarm = new DeviceAlarm(); |
|||
deviceAlarm.setDeviceId(deviceId); |
|||
deviceAlarm.setAlarmPriority(XmlUtil.getText(rootElement, "AlarmPriority")); |
|||
deviceAlarm.setAlarmMethod(XmlUtil.getText(rootElement, "AlarmMethod")); |
|||
deviceAlarm.setAlarmTime(XmlUtil.getText(rootElement, "AlarmTime")); |
|||
if (XmlUtil.getText(rootElement, "AlarmDescription") == null) { |
|||
deviceAlarm.setAlarmDescription(""); |
|||
} else { |
|||
deviceAlarm.setAlarmDescription(XmlUtil.getText(rootElement, "AlarmDescription")); |
|||
} |
|||
if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Longitude"))) { |
|||
deviceAlarm.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude"))); |
|||
} else { |
|||
deviceAlarm.setLongitude(0.00); |
|||
} |
|||
if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Latitude"))) { |
|||
deviceAlarm.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude"))); |
|||
} else { |
|||
deviceAlarm.setLatitude(0.00); |
|||
} |
|||
|
|||
if ( deviceAlarm.getAlarmMethod().equals("4")) { |
|||
MobilePosition mobilePosition = new MobilePosition(); |
|||
mobilePosition.setDeviceId(deviceAlarm.getDeviceId()); |
|||
mobilePosition.setTime(deviceAlarm.getAlarmTime()); |
|||
mobilePosition.setLongitude(deviceAlarm.getLongitude()); |
|||
mobilePosition.setLatitude(deviceAlarm.getLatitude()); |
|||
mobilePosition.setReportSource("GPS Alarm"); |
|||
BaiduPoint bp = new BaiduPoint(); |
|||
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); |
|||
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat()); |
|||
mobilePosition.setGeodeticSystem("BD-09"); |
|||
mobilePosition.setCnLng(bp.getBdLng()); |
|||
mobilePosition.setCnLat(bp.getBdLat()); |
|||
if (!userSetup.getSavePositionHistory()) { |
|||
storager.clearMobilePositionsByDeviceId(deviceId); |
|||
} |
|||
storager.insertMobilePosition(mobilePosition); |
|||
} |
|||
// TODO: 需要实现存储报警信息、报警分类
|
|||
|
|||
// 回复200 OK
|
|||
response200Ok(evt); |
|||
if (offLineDetector.isOnline(deviceId)) { |
|||
publisher.deviceAlarmEventPublish(deviceAlarm); |
|||
} |
|||
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
/*** |
|||
* 处理catalog设备目录列表Notify |
|||
* |
|||
* @param evt |
|||
*/ |
|||
private void processNotifyCatalogList(RequestEvent evt) { |
|||
try { |
|||
Element rootElement = getRootElement(evt); |
|||
Element deviceIdElement = rootElement.element("DeviceID"); |
|||
String deviceId = deviceIdElement.getText(); |
|||
Element deviceListElement = rootElement.element("DeviceList"); |
|||
if (deviceListElement == null) { |
|||
return; |
|||
} |
|||
Iterator<Element> deviceListIterator = deviceListElement.elementIterator(); |
|||
if (deviceListIterator != null) { |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
if (device == null) { |
|||
return; |
|||
} |
|||
// 遍历DeviceList
|
|||
while (deviceListIterator.hasNext()) { |
|||
Element itemDevice = deviceListIterator.next(); |
|||
Element channelDeviceElement = itemDevice.element("DeviceID"); |
|||
if (channelDeviceElement == null) { |
|||
continue; |
|||
} |
|||
String channelDeviceId = channelDeviceElement.getTextTrim(); |
|||
Element channdelNameElement = itemDevice.element("Name"); |
|||
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : ""; |
|||
Element statusElement = itemDevice.element("Status"); |
|||
String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON"; |
|||
DeviceChannel deviceChannel = new DeviceChannel(); |
|||
deviceChannel.setName(channelName); |
|||
deviceChannel.setChannelId(channelDeviceId); |
|||
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
|
|||
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { |
|||
deviceChannel.setStatus(1); |
|||
} |
|||
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { |
|||
deviceChannel.setStatus(0); |
|||
} |
|||
|
|||
deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer")); |
|||
deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model")); |
|||
deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner")); |
|||
deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode")); |
|||
deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block")); |
|||
deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address")); |
|||
if (XmlUtil.getText(itemDevice, "Parental") == null || XmlUtil.getText(itemDevice, "Parental") == "") { |
|||
deviceChannel.setParental(0); |
|||
} else { |
|||
deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental"))); |
|||
} |
|||
deviceChannel.setParentId(XmlUtil.getText(itemDevice, "ParentID")); |
|||
if (XmlUtil.getText(itemDevice, "SafetyWay") == null || XmlUtil.getText(itemDevice, "SafetyWay")== "") { |
|||
deviceChannel.setSafetyWay(0); |
|||
} else { |
|||
deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay"))); |
|||
} |
|||
if (XmlUtil.getText(itemDevice, "RegisterWay") == null || XmlUtil.getText(itemDevice, "RegisterWay") =="") { |
|||
deviceChannel.setRegisterWay(1); |
|||
} else { |
|||
deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay"))); |
|||
} |
|||
deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum")); |
|||
if (XmlUtil.getText(itemDevice, "Certifiable") == null || XmlUtil.getText(itemDevice, "Certifiable") == "") { |
|||
deviceChannel.setCertifiable(0); |
|||
} else { |
|||
deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable"))); |
|||
} |
|||
if (XmlUtil.getText(itemDevice, "ErrCode") == null || XmlUtil.getText(itemDevice, "ErrCode") == "") { |
|||
deviceChannel.setErrCode(0); |
|||
} else { |
|||
deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode"))); |
|||
} |
|||
deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime")); |
|||
deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy")); |
|||
deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress")); |
|||
if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") =="") { |
|||
deviceChannel.setPort(0); |
|||
} else { |
|||
deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port"))); |
|||
} |
|||
deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password")); |
|||
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) { |
|||
deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude"))); |
|||
} else { |
|||
deviceChannel.setLongitude(0.00); |
|||
} |
|||
if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) { |
|||
deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude"))); |
|||
} else { |
|||
deviceChannel.setLatitude(0.00); |
|||
} |
|||
if (XmlUtil.getText(itemDevice, "PTZType") == null || XmlUtil.getText(itemDevice, "PTZType") == "") { |
|||
deviceChannel.setPTZType(0); |
|||
} else { |
|||
deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType"))); |
|||
} |
|||
deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC
|
|||
storager.updateChannel(device.getDeviceId(), deviceChannel); |
|||
} |
|||
|
|||
// RequestMessage msg = new RequestMessage();
|
|||
// msg.setDeviceId(deviceId);
|
|||
// msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
|
|||
// msg.setData(device);
|
|||
// deferredResultHolder.invokeResult(msg);
|
|||
// 回复200 OK
|
|||
response200Ok(evt); |
|||
if (offLineDetector.isOnline(deviceId)) { |
|||
publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); |
|||
} |
|||
} |
|||
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
|
|||
/*** |
|||
* 回复200 OK |
|||
* @param evt |
|||
* @throws SipException |
|||
* @throws InvalidArgumentException |
|||
* @throws ParseException |
|||
*/ |
|||
private void response200Ok(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { |
|||
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); |
|||
getServerTransaction(evt).sendResponse(response); |
|||
} |
|||
|
|||
private Element getRootElement(RequestEvent evt) throws DocumentException { |
|||
Request request = evt.getRequest(); |
|||
SAXReader reader = new SAXReader(); |
|||
reader.setEncoding("gbk"); |
|||
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent())); |
|||
return xml.getRootElement(); |
|||
} |
|||
|
|||
public void setCmder(SIPCommander cmder) { |
|||
this.cmder = cmder; |
|||
} |
|||
|
|||
public void setStorager(IVideoManagerStorager storager) { |
|||
this.storager = storager; |
|||
} |
|||
|
|||
public void setPublisher(EventPublisher publisher) { |
|||
this.publisher = publisher; |
|||
} |
|||
|
|||
public void setRedis(RedisUtil redis) { |
|||
this.redis = redis; |
|||
} |
|||
|
|||
public void setDeferredResultHolder(DeferredResultHolder deferredResultHolder) { |
|||
this.deferredResultHolder = deferredResultHolder; |
|||
} |
|||
|
|||
public void setOffLineDetector(DeviceOffLineDetector offLineDetector) { |
|||
this.offLineDetector = offLineDetector; |
|||
} |
|||
|
|||
public IRedisCatchStorage getRedisCatchStorage() { |
|||
return redisCatchStorage; |
|||
} |
|||
|
|||
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { |
|||
this.redisCatchStorage = redisCatchStorage; |
|||
} |
|||
} |
@ -0,0 +1,41 @@ |
|||
package com.genersoft.iot.vmp.gb28181.utils; |
|||
|
|||
/** |
|||
* 数值格式判断和处理 |
|||
* @author lawrencehj |
|||
* @date 2021年1月27日 |
|||
*/ |
|||
public class NumericUtil { |
|||
|
|||
/** |
|||
* 判断是否Double格式 |
|||
* @param str |
|||
* @return true/false |
|||
*/ |
|||
public static boolean isDouble(String str) { |
|||
try { |
|||
Double num2 = Double.valueOf(str); |
|||
System.out.println(num2 + " Is an Integer!"); |
|||
return true; |
|||
} catch (Exception e) { |
|||
System.out.println(str + " Is not an Integer!"); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 判断是否Double格式 |
|||
* @param str |
|||
* @return true/false |
|||
*/ |
|||
public static boolean isInteger(String str) { |
|||
try { |
|||
int num2 = Integer.valueOf(str); |
|||
System.out.println(num2 + " Is Number!"); |
|||
return true; |
|||
} catch (Exception e) { |
|||
System.out.println(str + " Is not Number!"); |
|||
return false; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,33 @@ |
|||
package com.genersoft.iot.vmp.storager.dao; |
|||
|
|||
import java.util.List; |
|||
|
|||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
|||
import org.apache.ibatis.annotations.*; |
|||
//import org.springframework.stereotype.Repository;
|
|||
|
|||
@Mapper |
|||
//@Repository
|
|||
public interface DeviceMobilePositionMapper { |
|||
|
|||
@Insert("INSERT INTO device_mobile_position (deviceId, deviceName, time, longitude, latitude, altitude, speed, direction, reportSource, geodeticSystem, cnLng, cnLat) " + |
|||
"VALUES ('${deviceId}', '${deviceName}', '${time}', ${longitude}, ${latitude}, ${altitude}, ${speed}, ${direction}, '${reportSource}', '${geodeticSystem}', '${cnLng}', '${cnLat}')") |
|||
int insertNewPosition(MobilePosition mobilePosition); |
|||
|
|||
@Select(value = {" <script>" + |
|||
"SELECT * FROM device_mobile_position" + |
|||
" WHERE deviceId = #{deviceId} " + |
|||
"<if test=\"startTime != null\"> AND time>=#{startTime}</if>" + |
|||
"<if test=\"endTime != null\"> AND time<=#{endTime}</if>" + |
|||
" ORDER BY time ASC" + |
|||
" </script>"}) |
|||
List<MobilePosition> queryPositionByDeviceIdAndTime(String deviceId, String startTime, String endTime); |
|||
|
|||
@Select("SELECT * FROM device_mobile_position WHERE deviceId = #{deviceId}" + |
|||
" ORDER BY time DESC LIMIT 1") |
|||
MobilePosition queryLatestPositionByDevice(String deviceId); |
|||
|
|||
@Delete("DELETE FROM device_mobile_position WHERE deviceId = #{deviceId}") |
|||
int clearMobilePositionsByDeviceId(String deviceId); |
|||
|
|||
} |
@ -0,0 +1,68 @@ |
|||
package com.genersoft.iot.vmp.utils; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.InputStreamReader; |
|||
import java.io.OutputStream; |
|||
import java.net.Socket; |
|||
import java.util.Base64; |
|||
|
|||
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint; |
|||
|
|||
public class GpsUtil { |
|||
public static BaiduPoint Wgs84ToBd09(String xx, String yy) { |
|||
try { |
|||
Socket s = new Socket("api.map.baidu.com", 80); |
|||
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); |
|||
OutputStream out = s.getOutputStream(); |
|||
StringBuffer sb = new StringBuffer("GET /ag/coord/convert?from=0&to=4"); |
|||
sb.append("&x=" + xx + "&y=" + yy); |
|||
sb.append("&callback=BMap.Convertor.cbk_3976 HTTP/1.1\r\n"); |
|||
sb.append("User-Agent: Java/1.6.0_20\r\n"); |
|||
sb.append("Host: api.map.baidu.com:80\r\n"); |
|||
sb.append("Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n"); |
|||
sb.append("Connection: Close\r\n"); |
|||
sb.append("\r\n"); |
|||
out.write(sb.toString().getBytes()); |
|||
String json = ""; |
|||
String tmp = ""; |
|||
while ((tmp = br.readLine()) != null) { |
|||
// System.out.println(tmp);
|
|||
json += tmp; |
|||
} |
|||
|
|||
s.close(); |
|||
int start = json.indexOf("cbk_3976"); |
|||
int end = json.lastIndexOf("}"); |
|||
if (start != -1 && end != -1 && json.contains("\"x\":\"")) { |
|||
json = json.substring(start, end); |
|||
String[] point = json.split(","); |
|||
String x = point[1].split(":")[1].replace("\"", ""); |
|||
String y = point[2].split(":")[1].replace("\"", ""); |
|||
BaiduPoint bdPoint= new BaiduPoint(); |
|||
bdPoint.setBdLng(new String(decode(x))); |
|||
bdPoint.setBdLat(new String(decode(y))); |
|||
return bdPoint; |
|||
//return (new String(decode(x)) + "," + new String(decode(y)));
|
|||
} else { |
|||
System.out.println("gps坐标无效!!"); |
|||
} |
|||
out.close(); |
|||
br.close(); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* BASE64解码 |
|||
* @param str |
|||
* @return string |
|||
*/ |
|||
public static byte[] decode(String str) { |
|||
byte[] bt = null; |
|||
final Base64.Decoder decoder = Base64.getDecoder(); |
|||
bt = decoder.decode(str); // .decodeBuffer(str);
|
|||
return bt; |
|||
} |
|||
} |
@ -0,0 +1,118 @@ |
|||
package com.genersoft.iot.vmp.vmanager.MobilePosition; |
|||
|
|||
import java.util.List; |
|||
|
|||
import javax.sip.message.Response; |
|||
|
|||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|||
import com.github.pagehelper.util.StringUtil; |
|||
|
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.CrossOrigin; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.context.request.async.DeferredResult; |
|||
|
|||
@CrossOrigin |
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class MobilePositionController { |
|||
|
|||
private final static Logger logger = LoggerFactory.getLogger(MobilePositionController.class); |
|||
|
|||
@Autowired |
|||
private IVideoManagerStorager storager; |
|||
|
|||
@Autowired |
|||
private SIPCommander cmder; |
|||
|
|||
@Autowired |
|||
private DeferredResultHolder resultHolder; |
|||
|
|||
@GetMapping("/positions/{deviceId}/history") |
|||
public ResponseEntity<List<MobilePosition>> positions(@PathVariable String deviceId, |
|||
@RequestParam(required = false) String start, |
|||
@RequestParam(required = false) String end) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("查询设备" + deviceId + "的历史轨迹"); |
|||
} |
|||
|
|||
if (StringUtil.isEmpty(start)) { |
|||
start = null; |
|||
} |
|||
if (StringUtil.isEmpty(end)) { |
|||
end = null; |
|||
} |
|||
|
|||
List<MobilePosition> result = storager.queryMobilePositions(deviceId, start, end); |
|||
return new ResponseEntity<>(result, HttpStatus.OK); |
|||
} |
|||
|
|||
@GetMapping("/positions/{deviceId}/latest") |
|||
public ResponseEntity<MobilePosition> latestPosition(@PathVariable String deviceId) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("查询设备" + deviceId + "的最新位置"); |
|||
} |
|||
MobilePosition result = storager.queryLatestPosition(deviceId); |
|||
return new ResponseEntity<>(result, HttpStatus.OK); |
|||
} |
|||
|
|||
@GetMapping("/positions/{deviceId}/realtime") |
|||
public DeferredResult<ResponseEntity<MobilePosition>> realTimePosition(@PathVariable String deviceId) { |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
cmder.mobilePostitionQuery(device, event -> { |
|||
Response response = event.getResponse(); |
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_MOBILEPOSITION + deviceId); |
|||
msg.setData(String.format("获取移动位置信息失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
DeferredResult<ResponseEntity<MobilePosition>> result = new DeferredResult<ResponseEntity<MobilePosition>>(5*1000L); |
|||
result.onTimeout(()->{ |
|||
logger.warn(String.format("获取移动位置信息超时")); |
|||
// 释放rtpserver
|
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId); |
|||
msg.setData("Timeout"); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); |
|||
return result; |
|||
} |
|||
|
|||
@GetMapping("/positions/{deviceId}/subscribe") |
|||
public ResponseEntity<String> positionSubscribe(@PathVariable String deviceId, |
|||
@RequestParam String expires, |
|||
@RequestParam String interval) { |
|||
String msg = ((expires.equals("0")) ? "取消" : "") + "订阅设备" + deviceId + "的移动位置"; |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug(msg); |
|||
} |
|||
|
|||
if (StringUtil.isEmpty(interval)) { |
|||
interval = "5"; |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
|
|||
String result = msg; |
|||
if (cmder.mobilePositionSubscribe(device, Integer.parseInt(expires), Integer.parseInt(interval))) { |
|||
result += ",成功"; |
|||
} else { |
|||
result += ",失败"; |
|||
} |
|||
|
|||
return new ResponseEntity<>(result, HttpStatus.OK); |
|||
} |
|||
} |
@ -0,0 +1,121 @@ |
|||
/** |
|||
* 设备设置命令API接口 |
|||
* |
|||
* @author lawrencehj |
|||
* @date 2021年2月2日 |
|||
*/ |
|||
|
|||
package com.genersoft.iot.vmp.vmanager.device; |
|||
|
|||
import javax.sip.message.Response; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|||
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
|||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|||
|
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.springframework.web.context.request.async.DeferredResult; |
|||
|
|||
@CrossOrigin |
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class DeviceConfig { |
|||
|
|||
private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class); |
|||
|
|||
@Autowired |
|||
private IVideoManagerStorager storager; |
|||
|
|||
@Autowired |
|||
private SIPCommander cmder; |
|||
|
|||
@Autowired |
|||
private DeferredResultHolder resultHolder; |
|||
|
|||
/** |
|||
* 看守位控制命令API接口 |
|||
* |
|||
* @param deviceId |
|||
* @param enabled 看守位使能1:开启,0:关闭 |
|||
* @param resetTime 自动归位时间间隔(可选) |
|||
* @param presetIndex 调用预置位编号(可选) |
|||
* @param channelId 通道编码(可选) |
|||
*/ |
|||
@GetMapping("/config/{deviceId}/basicParam") |
|||
public DeferredResult<ResponseEntity<String>> homePositionApi(@PathVariable String deviceId, |
|||
@RequestParam(required = false) String channelId, |
|||
@RequestParam(required = false) String name, |
|||
@RequestParam(required = false) String expiration, |
|||
@RequestParam(required = false) String heartBeatInterval, |
|||
@RequestParam(required = false) String heartBeatCount) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("报警复位API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> { |
|||
Response response = event.getResponse(); |
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
msg.setData(String.format("设备配置操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|||
result.onTimeout(() -> { |
|||
logger.warn(String.format("设备配置操作超时, 设备未返回应答指令")); |
|||
// 释放rtpserver
|
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
JSONObject json = new JSONObject(); |
|||
json.put("DeviceID", deviceId); |
|||
json.put("Status", "Timeout"); |
|||
json.put("Description", "设备配置操作超时, 设备未返回应答指令"); |
|||
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 设备配置查询请求API接口 |
|||
* |
|||
* @param deviceId |
|||
*/ |
|||
@GetMapping("/config/{deviceId}/query/{configType}") |
|||
public DeferredResult<ResponseEntity<String>> configDownloadApi(@PathVariable String deviceId, |
|||
@PathVariable String configType, |
|||
@RequestParam(required = false) String channelId) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("设备状态查询API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
cmder.deviceConfigQuery(device, channelId, configType, event -> { |
|||
Response response = event.getResponse(); |
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
msg.setData(String.format("获取设备配置失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L); |
|||
result.onTimeout(()->{ |
|||
logger.warn(String.format("获取设备配置超时")); |
|||
// 释放rtpserver
|
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
msg.setData("Timeout. Device did not response to this command."); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|||
return result; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,238 @@ |
|||
/** |
|||
* 设备控制命令API接口 |
|||
* |
|||
* @author lawrencehj |
|||
* @date 2021年2月1日 |
|||
*/ |
|||
|
|||
package com.genersoft.iot.vmp.vmanager.device; |
|||
|
|||
import javax.sip.message.Response; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
|||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|||
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
|||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
|||
|
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.springframework.web.context.request.async.DeferredResult; |
|||
|
|||
@CrossOrigin |
|||
@RestController |
|||
@RequestMapping("/api") |
|||
public class DeviceControl { |
|||
|
|||
private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class); |
|||
|
|||
@Autowired |
|||
private IVideoManagerStorager storager; |
|||
|
|||
@Autowired |
|||
private SIPCommander cmder; |
|||
|
|||
@Autowired |
|||
private DeferredResultHolder resultHolder; |
|||
|
|||
/** |
|||
* 远程启动控制命令API接口 |
|||
* |
|||
* @param deviceId |
|||
*/ |
|||
@GetMapping("/control/{deviceId}/teleboot") |
|||
@PostMapping("/control/{deviceId}/teleboot") |
|||
public ResponseEntity<String> teleBootApi(@PathVariable String deviceId) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("设备远程启动API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
boolean sucsess = cmder.teleBootCmd(device); |
|||
if (sucsess) { |
|||
JSONObject json = new JSONObject(); |
|||
json.put("DeviceID", deviceId); |
|||
json.put("Result", "OK"); |
|||
return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK); |
|||
} else { |
|||
logger.warn("设备远程启动API调用失败!"); |
|||
return new ResponseEntity<String>("设备远程启动API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 录像控制命令API接口 |
|||
* |
|||
* @param deviceId |
|||
* @param recordCmdStr Record:手动录像,StopRecord:停止手动录像 |
|||
* @param channelId 通道编码(可选) |
|||
*/ |
|||
@GetMapping("/control/{deviceId}/record/{recordCmdStr}") |
|||
public DeferredResult<ResponseEntity<String>> recordApi(@PathVariable String deviceId, |
|||
@PathVariable String recordCmdStr, @RequestParam(required = false) String channelId) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("开始/停止录像API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
cmder.recordCmd(device, channelId, recordCmdStr, event -> { |
|||
Response response = event.getResponse(); |
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|||
result.onTimeout(() -> { |
|||
logger.warn(String.format("开始/停止录像操作超时, 设备未返回应答指令")); |
|||
// 释放rtpserver
|
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
msg.setData("Timeout. Device did not response to this command."); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 报警布防/撤防命令API接口 |
|||
* |
|||
* @param deviceId |
|||
* @param guardCmdStr SetGuard:布防,ResetGuard:撤防 |
|||
*/ |
|||
@GetMapping("/control/{deviceId}/guard/{guardCmdStr}") |
|||
public DeferredResult<ResponseEntity<String>> guardApi(@PathVariable String deviceId, @PathVariable String guardCmdStr) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("布防/撤防API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
cmder.guardCmd(device, guardCmdStr, event -> { |
|||
Response response = event.getResponse(); |
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|||
msg.setData(String.format("布防/撤防操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|||
result.onTimeout(() -> { |
|||
logger.warn(String.format("布防/撤防操作超时, 设备未返回应答指令")); |
|||
// 释放rtpserver
|
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|||
msg.setData("Timeout. Device did not response to this command."); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId, result); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 报警复位API接口 |
|||
* |
|||
* @param deviceId |
|||
* @param alarmMethod 报警方式(可选) |
|||
* @param alarmType 报警类型(可选) |
|||
*/ |
|||
@GetMapping("/control/{deviceId}/resetAlarm") |
|||
public DeferredResult<ResponseEntity<String>> resetAlarmApi(@PathVariable String deviceId, |
|||
@RequestParam(required = false) String alarmMethod, |
|||
@RequestParam(required = false) String alarmType) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("报警复位API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
cmder.alarmCmd(device, alarmMethod, alarmType, event -> { |
|||
Response response = event.getResponse(); |
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|||
msg.setData(String.format("报警复位操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|||
result.onTimeout(() -> { |
|||
logger.warn(String.format("报警复位操作超时, 设备未返回应答指令")); |
|||
// 释放rtpserver
|
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId); |
|||
msg.setData("Timeout. Device did not response to this command."); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId, result); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 强制关键帧API接口 |
|||
* |
|||
* @param deviceId |
|||
* @param channelId |
|||
*/ |
|||
@GetMapping("/control/{deviceId}/iFrame") |
|||
@PostMapping("/control/{deviceId}/iFrame") |
|||
public ResponseEntity<String> iFrame(@PathVariable String deviceId, |
|||
@RequestParam(required = false) String channelId) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("强制关键帧API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
boolean sucsess = cmder.iFrameCmd(device, channelId); |
|||
if (sucsess) { |
|||
JSONObject json = new JSONObject(); |
|||
json.put("DeviceID", deviceId); |
|||
json.put("ChannelID", channelId); |
|||
json.put("Result", "OK"); |
|||
return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK); |
|||
} else { |
|||
logger.warn("强制关键帧API调用失败!"); |
|||
return new ResponseEntity<String>("强制关键帧API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 看守位控制命令API接口 |
|||
* |
|||
* @param deviceId |
|||
* @param enabled 看守位使能1:开启,0:关闭 |
|||
* @param resetTime 自动归位时间间隔(可选) |
|||
* @param presetIndex 调用预置位编号(可选) |
|||
* @param channelId 通道编码(可选) |
|||
*/ |
|||
@GetMapping("/control/{deviceId}/homePosition/{enabled}") |
|||
public DeferredResult<ResponseEntity<String>> homePositionApi(@PathVariable String deviceId, |
|||
@PathVariable String enabled, |
|||
@RequestParam(required = false) String resetTime, |
|||
@RequestParam(required = false) String presetIndex, |
|||
@RequestParam(required = false) String channelId) { |
|||
if (logger.isDebugEnabled()) { |
|||
logger.debug("报警复位API调用"); |
|||
} |
|||
Device device = storager.queryVideoDevice(deviceId); |
|||
cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> { |
|||
Response response = event.getResponse(); |
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); |
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L); |
|||
result.onTimeout(() -> { |
|||
logger.warn(String.format("看守位控制操作超时, 设备未返回应答指令")); |
|||
// 释放rtpserver
|
|||
RequestMessage msg = new RequestMessage(); |
|||
msg.setId(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId)); |
|||
JSONObject json = new JSONObject(); |
|||
json.put("DeviceID", deviceId); |
|||
json.put("Status", "Timeout"); |
|||
json.put("Description", "看守位控制操作超时, 设备未返回应答指令"); |
|||
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
|
|||
resultHolder.invokeResult(msg); |
|||
}); |
|||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (XmlUtil.isEmpty(channelId) ? deviceId : channelId), result); |
|||
return result; |
|||
} |
|||
} |
Binary file not shown.
@ -0,0 +1,250 @@ |
|||
/** |
|||
* 经纬度转换 |
|||
*/ |
|||
export default { |
|||
PI: 3.1415926535897932384626, |
|||
//PI: 3.14159265358979324,
|
|||
x_pi: (3.1415926535897932384626 * 3000.0) / 180.0, |
|||
delta: function (lat, lng) { |
|||
// Krasovsky 1940
|
|||
//
|
|||
// a = 6378245.0, 1/f = 298.3
|
|||
// b = a * (1 - f)
|
|||
// ee = (a^2 - b^2) / a^2;
|
|||
var a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
|
|||
var ee = 0.00669342162296594323; // ee: 椭球的偏心率。
|
|||
var dLat = this.transformLat(lng - 105.0, lat - 35.0); |
|||
var dLng = this.transformLng(lng - 105.0, lat - 35.0); |
|||
var radLat = (lat / 180.0) * this.PI; |
|||
var magic = Math.sin(radLat); |
|||
magic = 1 - ee * magic * magic; |
|||
var sqrtMagic = Math.sqrt(magic); |
|||
dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * this.PI); |
|||
dLng = (dLng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * this.PI); |
|||
return { |
|||
lat: dLat, |
|||
lng: dLng |
|||
}; |
|||
}, |
|||
/** |
|||
* WGS-84 to GCJ-02 GPS坐标转中国坐标 |
|||
* @param {number} wgsLat GPS纬度 |
|||
* @param {number} wgsLng GPS经度 |
|||
* @return {object} 返回中国坐标经纬度对象 |
|||
*/ |
|||
GPSToChina: function (wgsLat, wgsLng) { |
|||
if (this.outOfChina(wgsLat, wgsLng)) return { |
|||
lat: wgsLat, |
|||
lng: wgsLng |
|||
}; |
|||
var d = this.delta(wgsLat, wgsLng); |
|||
return { |
|||
lat: Number(wgsLat) + Number(d.lat), |
|||
lng: Number(wgsLng) + Number(d.lng) |
|||
}; |
|||
}, |
|||
/** |
|||
* GCJ-02 to WGS-84 中国标准坐标转GPS坐标 |
|||
* @param {number} gcjLat 中国标准坐标纬度 |
|||
* @param {number} gcjLng 中国标准坐标经度 |
|||
* @return {object} 返回GPS经纬度对象 |
|||
*/ |
|||
chinaToGPS: function (gcjLat, gcjLng) { |
|||
if (this.outOfChina(gcjLat, gcjLng)) return { |
|||
lat: gcjLat, |
|||
lng: gcjLng |
|||
}; |
|||
var d = this.delta(gcjLat, gcjLng); |
|||
return { |
|||
lat: Number(gcjLat) - Number(d.lat), |
|||
lng: Number(gcjLng) - Number(d.lng) |
|||
}; |
|||
}, |
|||
/** |
|||
* GCJ-02 to WGS-84 exactly 中国标准坐标转GPS坐标(精确) |
|||
* @param {number} gcjLat 中国标准坐标纬度 |
|||
* @param {number} gcjLng 中国标准坐标经度 |
|||
* @return {object} 返回GPS经纬度对象(精确) |
|||
*/ |
|||
chinaToGPSExact: function (gcjLat, gcjLng) { |
|||
var initDelta = 0.01; |
|||
var threshold = 0.000000001; |
|||
var dLat = initDelta, |
|||
dLng = initDelta; |
|||
var mLat = gcjLat - dLat, |
|||
mLng = gcjLng - dLng; |
|||
var pLat = gcjLat + dLat, |
|||
pLng = gcjLng + dLng; |
|||
var wgsLat, |
|||
wgsLng, |
|||
i = 0; |
|||
while (1) { |
|||
wgsLat = (mLat + pLat) / 2; |
|||
wgsLng = (mLng + pLng) / 2; |
|||
var tmp = this.gcj_encrypt(wgsLat, wgsLng); |
|||
dLat = tmp.lat - gcjLat; |
|||
dLng = tmp.lng - gcjLng; |
|||
if (Math.abs(dLat) < threshold && Math.abs(dLng) < threshold) break; |
|||
|
|||
if (dLat > 0) pLat = wgsLat; |
|||
else mLat = wgsLat; |
|||
if (dLng > 0) pLng = wgsLng; |
|||
else mLng = wgsLng; |
|||
|
|||
if (++i > 10000) break; |
|||
} |
|||
//console.log(i);
|
|||
return { |
|||
lat: wgsLat, |
|||
lng: wgsLng |
|||
}; |
|||
}, |
|||
/** |
|||
* GCJ-02 to BD-09 中国标准坐标转百度坐标(精确) |
|||
* @param {number} gcjLat 中国标准坐标纬度 |
|||
* @param {number} gcjLng 中国标准坐标经度 |
|||
* @return {object} 返回百度经纬度对象 |
|||
*/ |
|||
chinaToBaidu: function (gcjLat, gcjLng) { |
|||
var x = gcjLng, |
|||
y = gcjLat; |
|||
var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * this.x_pi); |
|||
var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * this.x_pi); |
|||
var bdLng = z * Math.cos(theta) + 0.0065; |
|||
var bdLat = z * Math.sin(theta) + 0.006; |
|||
return { |
|||
lat: bdLat, |
|||
lng: bdLng |
|||
}; |
|||
}, |
|||
/** |
|||
* BD-09 to GCJ-02 百度坐标转中国标准坐标 |
|||
* @param {number} bdLat 百度坐标纬度 |
|||
* @param {number} bdLng 百度坐标经度 |
|||
* @return {object} 返回中国标准经纬度对象 |
|||
*/ |
|||
baiduToChina: function (bdLat, bdLng) { |
|||
var x = bdLng - 0.0065, |
|||
y = bdLat - 0.006; |
|||
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_pi); |
|||
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_pi); |
|||
var gcjLng = z * Math.cos(theta); |
|||
var gcjLat = z * Math.sin(theta); |
|||
return { |
|||
lat: gcjLat, |
|||
lng: gcjLng |
|||
}; |
|||
}, |
|||
/** |
|||
* BD-09 to GCJ-02 百度坐标转gps坐标 |
|||
* @param {number} bdLat 百度坐标纬度 |
|||
* @param {number} bdLng 百度坐标经度 |
|||
* @return {object} 返回gps经纬度对象 |
|||
*/ |
|||
baiduToGPS: function (bdLat, bdLng) { |
|||
let china = this.baiduToChina(bdLat, bdLng); |
|||
return this.chinaToGPS(china.lat, china.lng); |
|||
}, |
|||
/** |
|||
* WGS-84 to to BD-09 GPS坐标转Baidu坐标 |
|||
* @param {number} gpsLat GPS纬度 |
|||
* @param {number} gpsLng GPS经度 |
|||
* @return {object} 返回百度经纬度对象 |
|||
*/ |
|||
GPSToBaidu: function (gpsLat, gpsLng) { |
|||
var china = this.GPSToChina(gpsLat, gpsLng); |
|||
return this.chinaToBaidu(china.lat, china.lng); |
|||
}, |
|||
/** |
|||
* WGS-84 to Web mercator GPS坐标转墨卡托坐标 |
|||
* @param {number} wgsLat GPS纬度 |
|||
* @param {number} wgsLng GPS经度 |
|||
* @return {object} 返回墨卡托经纬度对象 |
|||
*/ |
|||
GPSToMercator: function (wgsLat, wgsLng) { |
|||
var x = (wgsLng * 20037508.34) / 180; |
|||
var y = Math.log(Math.tan(((90 + wgsLat) * this.PI) / 360)) / (this.PI / 180); |
|||
y = (y * 20037508.34) / 180; |
|||
return { |
|||
lat: y, |
|||
lng: x |
|||
}; |
|||
/* |
|||
if ((Math.abs(wgsLng) > 180 || Math.abs(wgsLat) > 90)) |
|||
return null; |
|||
var x = 6378137.0 * wgsLng * 0.017453292519943295; |
|||
var a = wgsLat * 0.017453292519943295; |
|||
var y = 3189068.5 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a))); |
|||
return {'lat' : y, 'lng' : x}; |
|||
//*/
|
|||
}, |
|||
/** |
|||
* Web mercator to WGS-84 墨卡托坐标转GPS坐标 |
|||
* @param {number} mercatorLat 墨卡托纬度 |
|||
* @param {number} mercatorLng 墨卡托经度 |
|||
* @return {object} 返回GPS经纬度对象 |
|||
*/ |
|||
mercatorToGPS: function (mercatorLat, mercatorLng) { |
|||
var x = (mercatorLng / 20037508.34) * 180; |
|||
var y = (mercatorLat / 20037508.34) * 180; |
|||
y = (180 / this.PI) * (2 * Math.atan(Math.exp((y * this.PI) / 180)) - this.PI / 2); |
|||
return { |
|||
lat: y, |
|||
lng: x |
|||
}; |
|||
/* |
|||
if (Math.abs(mercatorLng) < 180 && Math.abs(mercatorLat) < 90) |
|||
return null; |
|||
if ((Math.abs(mercatorLng) > 20037508.3427892) || (Math.abs(mercatorLat) > 20037508.3427892)) |
|||
return null; |
|||
var a = mercatorLng / 6378137.0 * 57.295779513082323; |
|||
var x = a - (Math.floor(((a + 180.0) / 360.0)) * 360.0); |
|||
var y = (1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * mercatorLat) / 6378137.0)))) * 57.295779513082323; |
|||
return {'lat' : y, 'lng' : x}; |
|||
//*/
|
|||
}, |
|||
/** |
|||
* 两点之间的距离 |
|||
* @param {number} latA 起点纬度 |
|||
* @param {number} lngA 起点经度 |
|||
* @param {number} latB 终点纬度 |
|||
* @param {number} lngB 终点经度 |
|||
* @return {number} 返回距离(米) |
|||
*/ |
|||
distance: function (latA, lngA, latB, lngB) { |
|||
var earthR = 6371000; |
|||
var x = Math.cos((latA * this.PI) / 180) * Math.cos((latB * this.PI) / 180) * Math.cos(((lngA - lngB) * this.PI) / 180); |
|||
var y = Math.sin((latA * this.PI) / 180) * Math.sin((latB * this.PI) / 180); |
|||
var s = x + y; |
|||
if (s > 1) s = 1; |
|||
if (s < -1) s = -1; |
|||
var alpha = Math.acos(s); |
|||
var distance = alpha * earthR; |
|||
return distance; |
|||
}, |
|||
/** |
|||
* 是否在中国之外 |
|||
* @param {number} lat 纬度 |
|||
* @param {number} lng 经度 |
|||
* @return {boolean]} 返回结果真或假 |
|||
*/ |
|||
outOfChina: function (lat, lng) { |
|||
if (lat < 72.004 || lat > 137.8347) return true; |
|||
if (lng < 0.8293 || lng > 55.8271) return true; |
|||
return false; |
|||
}, |
|||
transformLat: function (x, y) { |
|||
var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); |
|||
ret += ((20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0) / 3.0; |
|||
ret += ((20.0 * Math.sin(y * this.PI) + 40.0 * Math.sin((y / 3.0) * this.PI)) * 2.0) / 3.0; |
|||
ret += ((160.0 * Math.sin((y / 12.0) * this.PI) + 320 * Math.sin((y * this.PI) / 30.0)) * 2.0) / 3.0; |
|||
return ret; |
|||
}, |
|||
transformLng: function (x, y) { |
|||
var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); |
|||
ret += ((20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0) / 3.0; |
|||
ret += ((20.0 * Math.sin(x * this.PI) + 40.0 * Math.sin((x / 3.0) * this.PI)) * 2.0) / 3.0; |
|||
ret += ((150.0 * Math.sin((x / 12.0) * this.PI) + 300.0 * Math.sin((x / 30.0) * this.PI)) * 2.0) / 3.0; |
|||
return ret; |
|||
} |
|||
}; |
@ -0,0 +1,388 @@ |
|||
<template> |
|||
<div id="devicePosition" style="height: 100%"> |
|||
<el-container style="height: 100%"> |
|||
<el-header> |
|||
<uiHeader></uiHeader> |
|||
</el-header> |
|||
<el-main> |
|||
<div style="background-color: #ffffff; position: relative; padding: 1rem 0.5rem 0.5rem 0.5rem; text-align: center;"> |
|||
<span style="font-size: 1rem; font-weight: 500">设备定位 ({{ parentChannelId == 0 ? deviceId : parentChannelId }})</span> |
|||
</div> |
|||
<div style="background-color: #ffffff; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left; font-size: 14px;"> |
|||
<el-button icon="el-icon-arrow-left" size="mini" style="margin-right: 1rem" type="primary" @click="showDevice">返回</el-button> |
|||
<!-- <span class="demonstration">从</span> --> |
|||
<el-date-picker v-model="searchFrom" type="datetime" placeholder="选择开始日期时间" default-time="00:00:00" size="mini" style="width: 11rem;" align="right" :picker-options="pickerOptions"></el-date-picker> |
|||
<el-date-picker v-model="searchTo" type="datetime" placeholder="选择结束日期时间" default-time="00:00:00" size="mini" style="width: 11rem;" align="right" :picker-options="pickerOptions"></el-date-picker> |
|||
<el-button-group> |
|||
<el-button icon="el-icon-search" size="mini" type="primary" @click="showHistoryPath">历史轨迹</el-button> |
|||
<el-button icon="el-icon-search" size="mini" style="margin-right: 1rem" type="primary" @click="showLatestPosition">最新位置</el-button> |
|||
</el-button-group> |
|||
<el-tag style="width: 5rem; text-align: center" size="medium">过期时间</el-tag> |
|||
<el-input-number size="mini" v-model="expired" :min="300" :controls="false" style="width: 4rem;"></el-input-number> |
|||
<el-tag style="width: 5rem; text-align: center" size="medium">上报周期</el-tag> |
|||
<el-input-number size="mini" v-model="interval" :min="1" :controls="false" style="width: 4rem;"></el-input-number> |
|||
<el-button-group> |
|||
<el-button icon="el-icon-search" size="mini" type="primary" @click="subscribeMobilePosition">位置订阅</el-button> |
|||
<el-button icon="el-icon-search" size="mini" type="primary" @click="unSubscribeMobilePosition">取消订阅</el-button> |
|||
</el-button-group> |
|||
<el-checkbox size="mini" style="margin-right: 1rem; float: right" v-model="autoList" @change="autoListChange" >自动刷新</el-checkbox> |
|||
</div> |
|||
<div class="mapContainer" style="background-color: #ffffff; position: relative; padding: 1rem 0.5rem 0.5rem 0.5rem; text-align: center; height: calc(100% - 10rem);"> |
|||
<div class="baidumap" id="allmap"></div> |
|||
</div> |
|||
</el-main> |
|||
</el-container> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import uiHeader from "./UiHeader.vue"; |
|||
import moment from "moment"; |
|||
import geoTools from "./GeoConvertTools.js"; |
|||
export default { |
|||
name: "devicePosition", |
|||
components: { |
|||
uiHeader, |
|||
}, |
|||
data() { |
|||
return { |
|||
pickerOptions: { |
|||
shortcuts: [{ |
|||
text: '今天', |
|||
onClick(picker) { |
|||
picker.$emit('pick', new Date()); |
|||
} |
|||
}, { |
|||
text: '昨天', |
|||
onClick(picker) { |
|||
const date = new Date(); |
|||
date.setTime(date.getTime() - 3600 * 1000 * 24); |
|||
picker.$emit('pick', date); |
|||
} |
|||
}, { |
|||
text: '一周前', |
|||
onClick(picker) { |
|||
const date = new Date(); |
|||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); |
|||
picker.$emit('pick', date); |
|||
} |
|||
}] |
|||
}, |
|||
deviceId: this.$route.params.deviceId, |
|||
showHistoryPosition: false, //显示历史轨迹 |
|||
startTime: null, |
|||
endTime: null, |
|||
searchFrom: null, |
|||
searchTo: null, |
|||
expired: 600, |
|||
interval: 5, |
|||
mobilePositionList: [], |
|||
mapPointList: [], |
|||
parentChannelId: this.$route.params.parentChannelId, |
|||
updateLooper: 0, //数据刷新轮训标志 |
|||
total: 0, |
|||
beforeUrl: "/videoList", |
|||
isLoging: false, |
|||
autoList: false, |
|||
}; |
|||
}, |
|||
mounted() { |
|||
this.initData(); |
|||
this.initBaiduMap(); |
|||
if (this.autoList) { |
|||
this.updateLooper = setInterval(this.initData, 5000); |
|||
} |
|||
}, |
|||
destroyed() { |
|||
// this.$destroy("videojs"); |
|||
clearTimeout(this.updateLooper); |
|||
}, |
|||
methods: { |
|||
initData: function () { |
|||
// if (this.parentChannelId == "" || this.parentChannelId == 0) { |
|||
// this.getDeviceChannelList(); |
|||
// } else { |
|||
// this.showSubchannels(); |
|||
// } |
|||
}, |
|||
initParam: function () { |
|||
// this.deviceId = this.$route.params.deviceId; |
|||
// this.parentChannelId = this.$route.params.parentChannelId; |
|||
// this.currentPage = parseInt(this.$route.params.page); |
|||
// this.count = parseInt(this.$route.params.count); |
|||
// if (this.parentChannelId == "" || this.parentChannelId == 0) { |
|||
// this.beforeUrl = "/videoList"; |
|||
// } |
|||
}, |
|||
initBaiduMap() { |
|||
this.map = new BMap.Map("allmap"); // 创建地图实例 |
|||
let points = []; |
|||
let point = new BMap.Point(116.231398, 39.567445); // 创建点坐标 |
|||
this.map.centerAndZoom(point, 5); // 初始化地图,设置中心点坐标和地图级别 |
|||
this.map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放 |
|||
this.map.addControl(new BMap.NavigationControl()); |
|||
this.map.addControl(new BMap.ScaleControl()); |
|||
this.map.addControl(new BMap.OverviewMapControl()); |
|||
this.map.addControl(new BMap.MapTypeControl()); |
|||
//map.setMapStyle({ style: 'midnight' }) //地图风格 |
|||
}, |
|||
currentChange: function (val) { |
|||
// var url = `/${this.$router.currentRoute.name}/${this.deviceId}/${this.parentChannelId}/${this.count}/${val}`; |
|||
// console.log(url); |
|||
// this.$router.push(url).then(() => { |
|||
// this.initParam(); |
|||
// this.initData(); |
|||
// }); |
|||
}, |
|||
handleSizeChange: function (val) { |
|||
// var url = `/${this.$router.currentRoute.name}/${this.$router.params.deviceId}/${this.$router.params.parentChannelId}/${val}/1`; |
|||
// this.$router.push(url).then(() => { |
|||
// this.initParam(); |
|||
// this.initData(); |
|||
// }); |
|||
}, |
|||
showDevice: function () { |
|||
this.$router.push(this.beforeUrl).then(() => { |
|||
this.initParam(); |
|||
this.initData(); |
|||
}); |
|||
}, |
|||
autoListChange: function () { |
|||
if (this.autoList) { |
|||
this.updateLooper = setInterval(this.initData, 1500); |
|||
} else { |
|||
window.clearInterval(this.updateLooper); |
|||
} |
|||
}, |
|||
showHistoryPath: function () { |
|||
this.map.clearOverlays(); |
|||
this.mapPointList = []; |
|||
this.mobilePositionList = []; |
|||
if (!!this.searchFrom) { |
|||
this.startTime = this.toGBString(this.searchFrom); |
|||
console.log(this.startTime); |
|||
} else{ |
|||
this.startTime = null; |
|||
} |
|||
if (!!this.searchTo) { |
|||
this.endTime = this.toGBString(this.searchTo); |
|||
console.log(this.endTime); |
|||
} else { |
|||
this.endTime = null; |
|||
} |
|||
let self = this; |
|||
this.$axios.get(`/api/positions/${this.deviceId}/history`, { |
|||
params: { |
|||
start: self.startTime, |
|||
end: self.endTime, |
|||
}, |
|||
}) |
|||
.then(function (res) { |
|||
self.total = res.data.length; |
|||
self.mobilePositionList = res.data; |
|||
console.log(self.mobilePositionList); |
|||
if (self.total == 0) { |
|||
self.$message({ |
|||
showClose: true, |
|||
message: '未找到符合条件的移动位置信息', |
|||
type: 'error' |
|||
}); |
|||
} else { |
|||
self.$nextTick(() => { |
|||
self.showMarkPoints(self); |
|||
}); |
|||
} |
|||
}) |
|||
.catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
showLatestPosition: function() { |
|||
this.map.clearOverlays(); |
|||
this.mapPointList = []; |
|||
this.mobilePositionList = []; |
|||
let self = this; |
|||
this.$axios.get(`/api/positions/${this.deviceId}/latest`) |
|||
.then(function (res) { |
|||
console.log(res.data); |
|||
self.total = res.data.length; |
|||
self.mobilePositionList.push(res.data); |
|||
console.log(self.mobilePositionList); |
|||
if (self.total == 0) { |
|||
self.$message({ |
|||
showClose: true, |
|||
message: '未找到符合条件的移动位置信息', |
|||
type: 'error' |
|||
}); |
|||
} else { |
|||
self.$nextTick(() => { |
|||
self.showMarkPoints(self); |
|||
}); |
|||
} |
|||
}) |
|||
.catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
subscribeMobilePosition: function() { |
|||
let self = this; |
|||
this.$axios.get(`/api/positions/${this.deviceId}/subscribe`, { |
|||
params: { |
|||
expires: self.expired, |
|||
interval: self.interval, |
|||
}, |
|||
}) |
|||
.then(function (res) { |
|||
console.log(res.data); |
|||
}) |
|||
.catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
unSubscribeMobilePosition: function() { |
|||
let self = this; |
|||
this.$axios.get(`/api/positions/${this.deviceId}/subscribe`, { |
|||
params: { |
|||
expires: 0, |
|||
interval: self.interval, |
|||
}, |
|||
}) |
|||
.then(function (res) { |
|||
console.log(res.data); |
|||
}) |
|||
.catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
toGBString: function (dateTime) { |
|||
return ( |
|||
dateTime.getFullYear() + |
|||
"-" + this.twoDigits(dateTime.getMonth() + 1) + |
|||
"-" + this.twoDigits(dateTime.getDate()) + |
|||
"T" + this.twoDigits(dateTime.getHours()) + |
|||
":" + this.twoDigits(dateTime.getMinutes()) + |
|||
":" + this.twoDigits(dateTime.getSeconds()) |
|||
); |
|||
}, |
|||
twoDigits: function (num) { |
|||
if (num < 10) { |
|||
return "0" + num; |
|||
} else { |
|||
return "" + num; |
|||
} |
|||
}, |
|||
showMarkPoints: function(self) { |
|||
let that = self; |
|||
let npointJ = null; |
|||
let npointW = null; |
|||
let point = null; |
|||
for (let i = 0; i < self.mobilePositionList.length; i++) { |
|||
if (self.mobilePositionList[i].geodeticSystem == "BD-09") { |
|||
npointJ = self.mobilePositionList[i].cnLng; |
|||
npointW = self.mobilePositionList[i].cnLat; |
|||
point = new BMap.Point(npointJ, npointW); |
|||
} else { |
|||
npointJ = self.mobilePositionList[i].longitude; |
|||
npointW = self.mobilePositionList[i].latitude; |
|||
let bd2 = geoTools.GPSToBaidu(npointJ, npointW); |
|||
point = new BMap.Point(bd2.lat, bd2.lng); |
|||
} |
|||
self.mapPointList.push(point); |
|||
let marker = new BMap.Marker(point); // 创建标注 |
|||
self.map.addOverlay(marker); // 将标注添加到地图中 |
|||
//提示信息 可以解析 HTML标签以及CSS |
|||
let infoWindow = new BMap.InfoWindow(`<p style='text-align:left;font-weight:800'>设备: ${self.mobilePositionList[i].deviceId}</p> |
|||
<p style='text-align:left;font-weight:0'>时间: ${self.mobilePositionList[i].time}</p>`); |
|||
// 鼠标移上标注点要发生的事 |
|||
marker.addEventListener("mouseover", function () { |
|||
this.openInfoWindow(infoWindow); |
|||
}); |
|||
// 鼠标移开标注点要发生的事 |
|||
marker.addEventListener("mouseout", function () { |
|||
this.closeInfoWindow(infoWindow); |
|||
}); |
|||
// 鼠标点击标注点要发生的事情 |
|||
marker.addEventListener("click", function () { |
|||
alert("点击"); |
|||
}); |
|||
} |
|||
let view = that.map.getViewport(eval(self.mapPointList)); |
|||
that.map.centerAndZoom(view.center, view.zoom); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.videoList { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
align-content: flex-start; |
|||
} |
|||
|
|||
.video-item { |
|||
position: relative; |
|||
width: 15rem; |
|||
height: 10rem; |
|||
margin-right: 1rem; |
|||
background-color: #000000; |
|||
} |
|||
|
|||
.video-item-img { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.video-item-img:after { |
|||
content: ""; |
|||
display: inline-block; |
|||
position: absolute; |
|||
z-index: 2; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 3rem; |
|||
height: 3rem; |
|||
background-image: url("../assets/loading.png"); |
|||
background-size: cover; |
|||
background-color: #000000; |
|||
} |
|||
|
|||
.video-item-title { |
|||
position: absolute; |
|||
bottom: 0; |
|||
color: #000000; |
|||
background-color: #ffffff; |
|||
line-height: 1.5rem; |
|||
padding: 0.3rem; |
|||
width: 14.4rem; |
|||
} |
|||
|
|||
.baidumap { |
|||
width: 100%; |
|||
height: 100%; |
|||
border: none; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
margin: auto; |
|||
} |
|||
|
|||
/* 去除百度地图版权那行字 和 百度logo */ |
|||
.baidumap > .BMap_cpyCtrl { |
|||
display: none !important; |
|||
} |
|||
.baidumap > .anchorBL { |
|||
display: none !important; |
|||
} |
|||
</style> |
Loading…
Reference in new issue