From 40a806329ce08d5f50795cf965ef773aa48fdd3e Mon Sep 17 00:00:00 2001
From: 648540858 <456panlinlin>
Date: 星期五, 15 四月 2022 09:37:33 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/wvp-28181-2.0' into map

---
 src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java                                                 |    5 
 src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java                                                                            |   91 ++-
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java                                                               |   24 +
 src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java                                                   |    7 
 src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java                                                                     |  126 +++++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                                                   |   27 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java                                                             |   51 ++
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java                                                      |  110 +++-
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java                            |   30 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java       |   27 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java                                                                 |   22 
 src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java                                                    |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java                      |   13 
 web_src/src/components/dialog/SyncChannelProgress.vue                                                                             |  102 ++++
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                                                      |    1 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java |   13 
 src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java                                            |   33 +
 src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java                                                              |    1 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java                                            |    1 
 src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java                                     |   71 +-
 src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java                                                                         |   58 ++
 src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java                                       |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java         |   37 
 web_src/src/components/DeviceList.vue                                                                                             |   62 +-
 src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java                                                           |   50 +
 src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java                                                         |   72 ++
 src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java                                                              |    4 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java   |   33 +
 src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java                                                         |   42 +
 README.md                                                                                                                         |   11 
 src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java                                                             |    4 
 src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java                                                                   |   21 
 /dev/null                                                                                                                         |   49 --
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                                                            |    4 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java                                                                  |   34 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java                                        |  116 +++-
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java                                                            |    1 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java                               |    4 
 src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java                                                         |    3 
 39 files changed, 1,024 insertions(+), 340 deletions(-)

diff --git a/README.md b/README.md
index 2592bf0..69645b0 100644
--- a/README.md
+++ b/README.md
@@ -130,5 +130,14 @@
 
 
 # 鑷磋阿
-鎰熻阿浣滆�匸澶忔](https://github.com/xia-chu) 鎻愪緵杩欎箞妫掔殑寮�婧愭祦濯掍綋鏈嶅姟妗嗘灦  
+鎰熻阿浣滆�匸澶忔](https://github.com/xia-chu) 鎻愪緵杩欎箞妫掔殑寮�婧愭祦濯掍綋鏈嶅姟妗嗘灦,骞跺湪寮�鍙戣繃绋嬩腑缁欎簣鏀寔涓庡府鍔┿��     
+鎰熻阿浣滆�匸dexter langhuihui](https://github.com/langhuihui) 寮�婧愯繖涔堝ソ鐢ㄧ殑WEB鎾斁鍣ㄣ��     
+鎰熻阿浣滆�匸Kyle](https://gitee.com/kkkkk5G) 寮�婧愪簡濂界敤鐨勫墠绔〉闈�     
+鎰熻阿鍚勪綅澶т浆鐨勮禐鍔╀互鍙婂椤圭洰鐨勬寚姝d笌甯姪銆傚寘鎷絾涓嶉檺浜庝唬鐮佽础鐚�侀棶棰樺弽棣堛�佽祫閲戞崘璧犵瓑鍚勭鏂瑰紡鐨勬敮鎸侊紒浠ヤ笅鎺掑悕涓嶅垎鍏堝悗锛�  
+[lawrencehj](https://github.com/lawrencehj) @闄嗕赴-鍒涘绉戞妧 [swwhaha](https://github.com/swwheihei) 
+[hotcoffie](https://github.com/hotcoffie) [xiaomu](https://github.com/nikmu) [TristingChen](https://github.com/TristingChen)
+[chenparty](https://github.com/chenparty) [Hotleave](https://github.com/hotleave) [ydwxb](https://github.com/ydwxb)
+[ydpd](https://github.com/ydpd) [szy833](https://github.com/szy833) [ydwxb](https://github.com/ydwxb)
+
+ps: 鍒氬鍔犱簡杩欎釜鍚嶅崟锛岃偗瀹氶仐婕忎簡涓�浜涘ぇ浣紝娆㈣繋澶т浆鑱旂郴鎴戞坊鍔犮��
 
diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
index c4d49a8..e1d7c49 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -22,6 +22,9 @@
 
 	public static final String DEVICE_PREFIX = "VMP_DEVICE_";
 
+	// 璁惧鍚屾瀹屾垚
+	public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_";
+
 	public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_";
 
 	public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_";
@@ -69,6 +72,7 @@
 
 	public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_";
 
+
 	//************************** redis 娑堟伅*********************************
 
 	// 娴佸彉鍖栫殑閫氱煡
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java b/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
index 0c57bde..bd10317 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
@@ -1,6 +1,9 @@
 package com.genersoft.iot.vmp.conf;
 
 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@@ -18,6 +21,8 @@
 @Component
 public class DynamicTask {
 
+    private Logger logger = LoggerFactory.getLogger(DynamicTask.class);
+
     @Autowired
     private ThreadPoolTaskScheduler threadPoolTaskScheduler;
 
@@ -26,7 +31,12 @@
 
     @Bean
     public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
-        return new ThreadPoolTaskScheduler();
+        ThreadPoolTaskScheduler schedulerPool = new ThreadPoolTaskScheduler();
+        schedulerPool.setPoolSize(300);
+        schedulerPool.setWaitForTasksToCompleteOnShutdown(true);
+        schedulerPool.setAwaitTerminationSeconds(10);
+        return schedulerPool;
+
     }
 
     /**
@@ -37,11 +47,24 @@
      * @return
      */
     public void startCron(String key, Runnable task, int cycleForCatalog) {
-        stop(key);
+        ScheduledFuture future = futureMap.get(key);
+        if (future != null) {
+            if (future.isCancelled()) {
+                logger.info("浠诲姟銆恵}銆戝凡瀛樺湪浣嗘槸鍏抽棴鐘舵�侊紒锛侊紒", key);
+            } else {
+                logger.info("浠诲姟銆恵}銆戝凡瀛樺湪涓斿凡鍚姩锛侊紒锛�", key);
+                return;
+            }
+        }
         // scheduleWithFixedDelay 蹇呴』绛夊緟涓婁竴涓换鍔$粨鏉熸墠寮�濮嬭鏃秔eriod锛� cycleForCatalog琛ㄧず鎵ц鐨勯棿闅�
-        ScheduledFuture future = threadPoolTaskScheduler.scheduleWithFixedDelay(task, cycleForCatalog * 1000L);
-        futureMap.put(key, future);
-        runnableMap.put(key, task);
+        future = threadPoolTaskScheduler.scheduleAtFixedRate(task, cycleForCatalog * 1000L);
+        if (future != null){
+            futureMap.put(key, future);
+            runnableMap.put(key, task);
+            logger.info("浠诲姟銆恵}銆戝惎鍔ㄦ垚鍔燂紒锛侊紒", key);
+        }else {
+            logger.info("浠诲姟銆恵}銆戝惎鍔ㄥけ璐ワ紒锛侊紒", key);
+        }
     }
 
     /**
@@ -53,13 +76,31 @@
      */
     public void startDelay(String key, Runnable task, int delay) {
         stop(key);
+        System.out.println("瀹氭椂浠诲姟寮�濮嬩簡");
         Date starTime = new Date(System.currentTimeMillis() + delay);
+
+        ScheduledFuture future = futureMap.get(key);
+        if (future != null) {
+            if (future.isCancelled()) {
+                logger.info("浠诲姟銆恵}銆戝凡瀛樺湪浣嗘槸鍏抽棴鐘舵�侊紒锛侊紒", key);
+            } else {
+                logger.info("浠诲姟銆恵}銆戝凡瀛樺湪涓斿凡鍚姩锛侊紒锛�", key);
+                return;
+            }
+        }
         // scheduleWithFixedDelay 蹇呴』绛夊緟涓婁竴涓换鍔$粨鏉熸墠寮�濮嬭鏃秔eriod锛� cycleForCatalog琛ㄧず鎵ц鐨勯棿闅�
-        ScheduledFuture future = threadPoolTaskScheduler.schedule(task, starTime);
-        futureMap.put(key, future);
+        future = threadPoolTaskScheduler.schedule(task, starTime);
+        if (future != null){
+            futureMap.put(key, future);
+            runnableMap.put(key, task);
+            logger.info("浠诲姟銆恵}銆戝惎鍔ㄦ垚鍔燂紒锛侊紒", key);
+        }else {
+            logger.info("浠诲姟銆恵}銆戝惎鍔ㄥけ璐ワ紒锛侊紒", key);
+        }
     }
 
     public void stop(String key) {
+        System.out.println("瀹氭椂浠诲姟缁撴潫浜�");
         if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) {
             futureMap.get(key).cancel(true);
             Runnable runnable = runnableMap.get(key);
@@ -78,4 +119,7 @@
         return futureMap.keySet();
     }
 
+    public Runnable get(String key) {
+        return runnableMap.get(key);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
index c74fb87..40f676e 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
@@ -8,6 +8,12 @@
     private List<DeviceChannel> channelList;
     private Date lastTime;
     private Device device;
+    private String errorMsg;
+
+    public enum CatalogDataStatus{
+        ready, runIng, end
+    }
+    private CatalogDataStatus status;
 
     public int getTotal() {
         return total;
@@ -40,4 +46,20 @@
     public void setDevice(Device device) {
         this.device = device;
     }
+
+    public String getErrorMsg() {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String errorMsg) {
+        this.errorMsg = errorMsg;
+    }
+
+    public CatalogDataStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(CatalogDataStatus status) {
+        this.status = status;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
index 62a45d5..981fe1e 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
@@ -1,5 +1,12 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
+import com.genersoft.iot.vmp.common.VideoManagerConstants;
+import com.genersoft.iot.vmp.conf.DynamicTask;
+import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.util.ArrayList;
@@ -9,12 +16,32 @@
 @Component
 public class SubscribeHolder {
 
+    @Autowired
+    private DynamicTask dynamicTask;
+
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
+    private ISIPCommanderForPlatform sipCommanderForPlatform;
+
+    @Autowired
+    private IVideoManagerStorage storager;
+
+    private final String taskOverduePrefix = "subscribe_overdue_";
+
     private static ConcurrentHashMap<String, SubscribeInfo> catalogMap = new ConcurrentHashMap<>();
     private static ConcurrentHashMap<String, SubscribeInfo> mobilePositionMap = new ConcurrentHashMap<>();
 
 
     public void putCatalogSubscribe(String platformId, SubscribeInfo subscribeInfo) {
         catalogMap.put(platformId, subscribeInfo);
+        // 娣诲姞璁㈤槄鍒版湡
+        String taskOverdueKey = taskOverduePrefix +  "catalog_" + platformId;
+        dynamicTask.stop(taskOverdueKey);
+        // 娣诲姞浠诲姟澶勭悊璁㈤槄杩囨湡
+        dynamicTask.startDelay(taskOverdueKey, () -> removeCatalogSubscribe(subscribeInfo.getId()),
+                subscribeInfo.getExpires() * 1000);
     }
 
     public SubscribeInfo getCatalogSubscribe(String platformId) {
@@ -23,10 +50,24 @@
 
     public void removeCatalogSubscribe(String platformId) {
         catalogMap.remove(platformId);
+        String taskOverdueKey = taskOverduePrefix +  "catalog_" + platformId;
+        // 娣诲姞浠诲姟澶勭悊璁㈤槄杩囨湡
+        dynamicTask.stop(taskOverdueKey);
     }
 
     public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo) {
         mobilePositionMap.put(platformId, subscribeInfo);
+        String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX +  "MobilePosition_" + platformId;
+        // 娣诲姞浠诲姟澶勭悊GPS瀹氭椂鎺ㄩ��
+        dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager,  platformId, subscribeInfo.getSn(), key, this), subscribeInfo.getGpsInterval());
+        String taskOverdueKey = taskOverduePrefix +  "MobilePosition_" + platformId;
+        dynamicTask.stop(taskOverdueKey);
+        // 娣诲姞浠诲姟澶勭悊璁㈤槄杩囨湡
+        dynamicTask.startDelay(taskOverdueKey, () -> {
+                    System.out.println("璁㈤槄杩囨湡");
+                    removeMobilePositionSubscribe(subscribeInfo.getId());
+                },
+                subscribeInfo.getExpires() * 1000);
     }
 
     public SubscribeInfo getMobilePositionSubscribe(String platformId) {
@@ -35,6 +76,12 @@
 
     public void removeMobilePositionSubscribe(String platformId) {
         mobilePositionMap.remove(platformId);
+        String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX +  "MobilePosition_" + platformId;
+        // 缁撴潫浠诲姟澶勭悊GPS瀹氭椂鎺ㄩ��
+        dynamicTask.stop(key);
+        String taskOverdueKey = taskOverduePrefix +  "MobilePosition_" + platformId;
+        // 娣诲姞浠诲姟澶勭悊璁㈤槄杩囨湡
+        dynamicTask.stop(taskOverdueKey);
     }
 
     public List<String> getAllCatalogSubscribePlatform() {
@@ -48,7 +95,7 @@
     }
 
     public void removeAllSubscribe(String platformId) {
-        mobilePositionMap.remove(platformId);
-        catalogMap.remove(platformId);
+        removeMobilePositionSubscribe(platformId);
+        removeCatalogSubscribe(platformId);
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
index 434a639..feb6a72 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
@@ -33,6 +33,14 @@
     private ServerTransaction transaction;
     private Dialog dialog;
 
+    /**
+     * 浠ヤ笅涓哄彲閫夊瓧娈�
+     * @return
+     */
+    private String sn;
+    private int gpsInterval;
+
+
     public String getId() {
         return id;
     }
@@ -88,4 +96,20 @@
     public void setDialog(Dialog dialog) {
         this.dialog = dialog;
     }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public int getGpsInterval() {
+        return gpsInterval;
+    }
+
+    public void setGpsInterval(int gpsInterval) {
+        this.gpsInterval = gpsInterval;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java
new file mode 100644
index 0000000..2ae50e6
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java
@@ -0,0 +1,34 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+/**
+ * 鎽勫儚鏈哄悓姝ョ姸鎬�
+ */
+public class SyncStatus {
+    private int total;
+    private int current;
+    private String errorMsg;
+
+    public int getTotal() {
+        return total;
+    }
+
+    public void setTotal(int total) {
+        this.total = total;
+    }
+
+    public int getCurrent() {
+        return current;
+    }
+
+    public void setCurrent(int current) {
+        this.current = current;
+    }
+
+    public String getErrorMsg() {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String errorMsg) {
+        this.errorMsg = errorMsg;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
index 5e4a3d4..b5c6bba 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
@@ -95,11 +95,12 @@
 		}
 		// 澶勭悊涓婄嚎鐩戝惉
 		storager.updateDevice(device);
-		List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(device.getDeviceId());
-		eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON);
 		// 涓婄嚎娣诲姞璁㈤槄
 		if (device.getSubscribeCycleForCatalog() > 0) {
+			// 鏌ヨ鍦ㄧ嚎璁惧閭d簺寮�鍚簡璁㈤槄锛屼负璁惧寮�鍚畾鏃剁殑鐩綍璁㈤槄
 			deviceService.addCatalogSubscribe(device);
+		}
+		if (device.getSubscribeCycleForMobilePosition() > 0) {
 			deviceService.addMobilePositionSubscribe(device);
 		}
 	}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java
deleted file mode 100644
index 9f0d0d5..0000000
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.genersoft.iot.vmp.gb28181.event.subscribe;
-
-import com.genersoft.iot.vmp.common.VideoManagerConstants;
-import com.genersoft.iot.vmp.conf.DynamicTask;
-import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;
-import com.genersoft.iot.vmp.conf.UserSetting;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.connection.Message;
-import org.springframework.data.redis.listener.RedisMessageListenerContainer;
-import org.springframework.stereotype.Component;
-
-/**    
- * 骞冲彴璁㈤槄鍒版湡浜嬩欢
- */
-@Component
-public class SubscribeListenerForPlatform extends RedisKeyExpirationEventMessageListener {
-
-    private Logger logger = LoggerFactory.getLogger(SubscribeListenerForPlatform.class);
-
-	@Autowired
-	private UserSetting userSetting;
-
-    @Autowired
-    private DynamicTask dynamicTask;
-
-    public SubscribeListenerForPlatform(RedisMessageListenerContainer listenerContainer, UserSetting userSetting) {
-        super(listenerContainer, userSetting);
-    }
-
-
-    /**
-     * 鐩戝惉澶辨晥鐨刱ey
-     * @param message
-     * @param pattern
-     */
-    @Override
-    public void onMessage(Message message, byte[] pattern) {
-        //  鑾峰彇澶辨晥鐨刱ey
-        String expiredKey = message.toString();
-        // 璁㈤槄鍒版湡
-        String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_";
-        if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) {
-            // 鍙栨秷瀹氭椂浠诲姟
-            dynamicTask.stop(expiredKey);
-        }
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
index dd7f394..019baf9 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
@@ -61,8 +61,6 @@
         if (event.getPlatformId() != null) {
             parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId());
             if (parentPlatform != null && !parentPlatform.isStatus())return;
-            String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() +  "_Catalog_" + event.getPlatformId();
-//            subscribe = redisCatchStorage.getSubscribe(key);
             subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
 
             if (subscribe == null) {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
index 8a3bc84..fbc2a32 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
@@ -3,6 +3,7 @@
 import com.genersoft.iot.vmp.gb28181.bean.CatalogData;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -25,6 +26,17 @@
     @Autowired
     private IVideoManagerStorage storager;
 
+    public void addReady(String key) {
+        CatalogData catalogData = data.get(key);
+        if (catalogData == null || catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end)) {
+            catalogData = new CatalogData();
+            catalogData.setChannelList(new ArrayList<>());
+            catalogData.setStatus(CatalogData.CatalogDataStatus.ready);
+            catalogData.setLastTime(new Date(System.currentTimeMillis()));
+            data.put(key, catalogData);
+        }
+    }
+
     public void put(String key, int total, Device device, List<DeviceChannel> deviceChannelList) {
         CatalogData catalogData = data.get(key);
         if (catalogData == null) {
@@ -32,16 +44,38 @@
             catalogData.setTotal(total);
             catalogData.setDevice(device);
             catalogData.setChannelList(new ArrayList<>());
+            catalogData.setStatus(CatalogData.CatalogDataStatus.runIng);
+            catalogData.setLastTime(new Date(System.currentTimeMillis()));
             data.put(key, catalogData);
+        }else {
+            catalogData.setTotal(total);
+            catalogData.setDevice(device);
+            catalogData.setStatus(CatalogData.CatalogDataStatus.runIng);
+            catalogData.getChannelList().addAll(deviceChannelList);
+            catalogData.setLastTime(new Date(System.currentTimeMillis()));
         }
-        catalogData.getChannelList().addAll(deviceChannelList);
-        catalogData.setLastTime(new Date(System.currentTimeMillis()));
     }
 
     public List<DeviceChannel> get(String key) {
         CatalogData catalogData = data.get(key);
         if (catalogData == null) return null;
         return catalogData.getChannelList();
+    }
+
+    public int getTotal(String key) {
+        CatalogData catalogData = data.get(key);
+        if (catalogData == null) return 0;
+        return catalogData.getTotal();
+    }
+
+    public SyncStatus getSyncStatus(String key) {
+        CatalogData catalogData = data.get(key);
+        if (catalogData == null) return null;
+        SyncStatus syncStatus = new SyncStatus();
+        syncStatus.setCurrent(catalogData.getChannelList().size());
+        syncStatus.setTotal(catalogData.getTotal());
+        syncStatus.setErrorMsg(catalogData.getErrorMsg());
+        return syncStatus;
     }
 
     public void del(String key) {
@@ -51,24 +85,32 @@
     @Scheduled(fixedRate = 5 * 1000)   //姣�5绉掓墽琛屼竴娆�, 鍙戠幇鏁版嵁5绉掓湭鏇存柊鍒欑Щ闄ゆ暟鎹苟璁や负鏁版嵁鎺ユ敹瓒呮椂
     private void timerTask(){
         Set<String> keys = data.keySet();
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) - 5);
+        Calendar calendarBefore5S = Calendar.getInstance();
+        calendarBefore5S.setTime(new Date());
+        calendarBefore5S.set(Calendar.SECOND, calendarBefore5S.get(Calendar.SECOND) - 5);
+
+        Calendar calendarBefore30S = Calendar.getInstance();
+        calendarBefore30S.setTime(new Date());
+        calendarBefore30S.set(Calendar.SECOND, calendarBefore30S.get(Calendar.SECOND) - 30);
         for (String key : keys) {
             CatalogData catalogData = data.get(key);
-            if (catalogData.getLastTime().before(calendar.getTime())) {
-
+            if (catalogData.getLastTime().before(calendarBefore5S.getTime())) { // 瓒呰繃浜旂鏀朵笉鍒版秷鎭换鍔¤秴鏃讹紝 鍙洿鏂拌繖涓�閮ㄥ垎鏁版嵁
                 storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList());
-                RequestMessage msg = new RequestMessage();
-                msg.setKey(key);
-                WVPResult<Object> result = new WVPResult<>();
-                result.setCode(0);
-                result.setMsg("鏇存柊鎴愬姛锛屽叡" + catalogData.getTotal() + "鏉★紝宸叉洿鏂�" + catalogData.getChannelList().size() + "鏉�");
-                result.setData(catalogData.getDevice());
-                msg.setData(result);
-                deferredResultHolder.invokeAllResult(msg);
+                String errorMsg = "鏇存柊鎴愬姛锛屽叡" + catalogData.getTotal() + "鏉★紝宸叉洿鏂�" + catalogData.getChannelList().size() + "鏉�";
+                catalogData.setStatus(CatalogData.CatalogDataStatus.end);
+                catalogData.setErrorMsg(errorMsg);
+            }
+            if (catalogData.getLastTime().before(calendarBefore30S.getTime())) { // 瓒呰繃涓夊崄绉掞紝濡傛灉鏍囪涓篹nd鍒欏垹闄�
                 data.remove(key);
             }
         }
     }
+
+
+    public void setChannelSyncEnd(String key, String errorMsg) {
+        CatalogData catalogData = data.get(key);
+        if (catalogData == null)return;
+        catalogData.setStatus(CatalogData.CatalogDataStatus.end);
+        catalogData.setErrorMsg(errorMsg);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
index 4c6a18a..b6ec451 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
@@ -1,5 +1,9 @@
 package com.genersoft.iot.vmp.gb28181.task;
 
+import javax.sip.DialogState;
+
 public interface ISubscribeTask extends Runnable{
     void stop();
+
+    DialogState getDialogState();
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
index 51356d5..bee5fba 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
@@ -5,6 +5,7 @@
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
 
 import javax.sip.Dialog;
 import javax.sip.DialogState;
@@ -72,4 +73,10 @@
             });
         }
     }
+
+    @Override
+    public DialogState getDialogState() {
+        if (dialog == null) return null;
+        return dialog.getState();
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
index fcac3e9..f20baf9 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
@@ -1,16 +1,16 @@
 package com.genersoft.iot.vmp.gb28181.task.impl;
 
-import com.genersoft.iot.vmp.gb28181.bean.GbStream;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
-import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
-import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
+import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
 
-import java.text.SimpleDateFormat;
+import javax.sip.DialogState;
 import java.util.List;
 
 /**
@@ -18,20 +18,21 @@
  */
 public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
 
+    private Logger logger = LoggerFactory.getLogger(MobilePositionSubscribeHandlerTask.class);
+
     private IRedisCatchStorage redisCatchStorage;
     private IVideoManagerStorage storager;
     private ISIPCommanderForPlatform sipCommanderForPlatform;
     private SubscribeHolder subscribeHolder;
-    private String platformId;
+    private ParentPlatform platform;
     private String sn;
     private String key;
 
-    private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
     public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) {
+        System.out.println("MobilePositionSubscribeHandlerTask 鍒濆鍖�");
         this.redisCatchStorage = redisCatchStorage;
         this.storager = storager;
-        this.platformId = platformId;
+        this.platform = storager.queryParentPlatByServerGBId(platformId);
         this.sn = sn;
         this.key = key;
         this.sipCommanderForPlatform = sipCommanderForPlatform;
@@ -41,37 +42,45 @@
     @Override
     public void run() {
 
-        SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platformId);
-
+        logger.info("鎵цMobilePositionSubscribeHandlerTask");
+        if (platform == null) return;
+        SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId());
         if (subscribe != null) {
-            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
-            if (parentPlatform == null || parentPlatform.isStatus()) {
-                // TODO 鏆傛椂鍙鐞嗚棰戞祦鐨勫洖澶�,鍚庣画澧炲姞瀵瑰浗鏍囪澶囩殑鏀寔
-                List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platformId);
-                if (gbStreams.size() > 0) {
-                    for (GbStream gbStream : gbStreams) {
-                        String gbId = gbStream.getGbId();
-                        GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
-                        if (gpsMsgInfo != null) {
-                            // 鍙戦�丟PS娑堟伅
-                            sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
-                        }else {
-                            // 娌℃湁鍦╮edis鎵惧埌鏂扮殑娑堟伅灏变娇鐢ㄦ暟鎹簱鐨勬秷鎭�
-                            gpsMsgInfo = new GPSMsgInfo();
-                            gpsMsgInfo.setId(gbId);
-                            gpsMsgInfo.setLat(gbStream.getLongitude());
-                            gpsMsgInfo.setLng(gbStream.getLongitude());
-                            // 鍙戦�丟PS娑堟伅
-                            sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
-                        }
+
+//            if (!parentPlatform.isStatus()) {
+//                logger.info("鍙戦�佽闃呮椂鍙戠幇骞冲彴宸茬粡绂荤嚎锛歿}", platformId);
+//                return;
+//            }
+            // TODO 鏆傛椂鍙鐞嗚棰戞祦鐨勫洖澶�,鍚庣画澧炲姞瀵瑰浗鏍囪澶囩殑鏀寔
+            List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId());
+            if (gbStreams.size() == 0) {
+                logger.info("鍙戦�佽闃呮椂鍙戠幇骞冲彴宸茬粡娌℃湁鍏宠仈鐨勭洿鎾祦锛歿}", platform.getServerGBId());
+                return;
+            }
+            for (GbStream gbStream : gbStreams) {
+                String gbId = gbStream.getGbId();
+                GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
+                if (gpsMsgInfo != null) { // 鏃犳渶鏂颁綅缃笉鍙戦��
+                    logger.info("鏃犳渶鏂颁綅缃笉鍙戦��");
+                    // 缁忕含搴﹂兘涓�0涓嶅彂閫�
+                    if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) {
+                        continue;
                     }
+                    // 鍙戦�丟PS娑堟伅
+                    sipCommanderForPlatform.sendNotifyMobilePosition(platform, gpsMsgInfo, subscribe);
                 }
             }
         }
+        logger.info("缁撴潫鎵цMobilePositionSubscribeHandlerTask");
     }
 
     @Override
     public void stop() {
 
     }
+
+    @Override
+    public DialogState getDialogState() {
+        return null;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
index f67f6d2..884f040 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
@@ -6,10 +6,13 @@
 import org.dom4j.Element;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
 
 import javax.sip.Dialog;
 import javax.sip.DialogState;
 import javax.sip.ResponseEvent;
+import java.util.Timer;
+import java.util.TimerTask;
 
 /**
  * 绉诲姩浣嶇疆璁㈤槄鐨勫畾鏃舵洿鏂�
@@ -20,6 +23,8 @@
     private  ISIPCommander sipCommander;
     private Dialog dialog;
 
+    private Timer timer ;
+
     public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander) {
         this.device = device;
         this.sipCommander = sipCommander;
@@ -27,10 +32,14 @@
 
     @Override
     public void run() {
+        if (timer != null ) {
+            timer.cancel();
+            timer = null;
+        }
         sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> {
-            if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) {
-                dialog = eventResult.dialog;
-            }
+//            if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) {
+//                dialog = eventResult.dialog;
+//            }
             ResponseEvent event = (ResponseEvent) eventResult.event;
             if (event.getResponse().getRawContent() != null) {
                 // 鎴愬姛
@@ -43,6 +52,13 @@
             dialog = null;
             // 澶辫触
             logger.warn("[绉诲姩浣嶇疆璁㈤槄]澶辫触锛屼俊浠ゅ彂閫佸け璐ワ細 {}-{} ", device.getDeviceId(), eventResult.msg);
+            timer = new Timer();
+            timer.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    MobilePositionSubscribeTask.this.run();
+                }
+            }, 2000);
         });
 
     }
@@ -56,8 +72,12 @@
          * COMPLETED-> Completed Dialog鐘舵��-宸插畬鎴�
          * TERMINATED-> Terminated Dialog鐘舵��-缁堟
          */
-        logger.info("鍙栨秷绉诲姩璁㈤槄鏃禿ialog鐘舵�佷负{}", dialog.getState());
+        if (timer != null ) {
+            timer.cancel();
+            timer = null;
+        }
         if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) {
+            logger.info("鍙栨秷绉诲姩璁㈤槄鏃禿ialog鐘舵�佷负{}", dialog.getState());
             device.setSubscribeCycleForMobilePosition(0);
             sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> {
                 ResponseEvent event = (ResponseEvent) eventResult.event;
@@ -74,4 +94,9 @@
             });
         }
     }
+    @Override
+    public DialogState getDialogState() {
+        if (dialog == null) return null;
+        return dialog.getState();
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
index 1f58a15..a900819 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
@@ -46,6 +46,7 @@
      * @return
      */
     boolean catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size);
+    boolean catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag);
 
     /**
      * 鍚戜笂绾у洖澶岲eviceInfo鏌ヨ淇℃伅
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
index 123d0e7..027238b 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -1566,17 +1566,28 @@
 			cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			cmdXml.append("</Query>\r\n");
 
-			String tm = Long.toString(System.currentTimeMillis());
 
-			CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
-					: udpSipProvider.getNewCallId();
+			Request request;
+			if (dialog != null) {
+				logger.info("鍙戦�佺洰褰曡闃呮秷鎭椂 dialog鐨勭姸鎬佷负锛� {}", dialog.getState());
+				request = dialog.createRequest(Request.SUBSCRIBE);
+				ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
+				request.setContent(cmdXml.toString(), contentTypeHeader);
+				ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForMobilePosition());
+				request.addHeader(expireHeader);
+			}else {
+				String tm = Long.toString(System.currentTimeMillis());
 
-			// 鏈夋晥鏃堕棿榛樿涓�60绉掍互涓�
-			Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
-					"fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
-					callIdHeader);
+				CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
+						: udpSipProvider.getNewCallId();
+
+				// 鏈夋晥鏃堕棿榛樿涓�60绉掍互涓�
+				request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
+						"fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
+						callIdHeader);
+
+			}
 			transmitRequest(device, request, errorEvent, okEvent);
-
 			return true;
 
 		} catch ( NumberFormatException | ParseException | InvalidArgumentException	| SipException e) {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
index 9c22ad9..c5cdae0 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -215,44 +215,7 @@
             return false;
         }
         try {
-            String characterSet = parentPlatform.getCharacterSet();
-            StringBuffer catalogXml = new StringBuffer(600);
-            catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet +"\"?>\r\n");
-            catalogXml.append("<Response>\r\n");
-            catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
-            catalogXml.append("<SN>" +sn + "</SN>\r\n");
-            catalogXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n");
-            catalogXml.append("<SumNum>" + size + "</SumNum>\r\n");
-            catalogXml.append("<DeviceList Num=\"1\">\r\n");
-            catalogXml.append("<Item>\r\n");
-            if (channel != null) {
-                catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
-                catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
-                catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
-                catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
-                catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n");
-                catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
-                catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
-                catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
-                if (channel.getParentId() != null) {
-                    catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
-                }
-                catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
-                catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
-                catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n");
-                catalogXml.append("<Longitude>" + channel.getLongitude() + "</Longitude>\r\n");
-                catalogXml.append("<Latitude>" + channel.getLatitude() + "</Latitude>\r\n");
-                catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
-                catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
-                catalogXml.append("<Info>\r\n");
-                catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
-                catalogXml.append("</Info>\r\n");
-            }
-
-
-            catalogXml.append("</Item>\r\n");
-            catalogXml.append("</DeviceList>\r\n");
-            catalogXml.append("</Response>\r\n");
+            String catalogXml = getCatalogXml(channel, sn, parentPlatform, size);
 
             // callid
             CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
@@ -266,6 +229,77 @@
             return false;
         }
         return true;
+    }
+
+    @Override
+    public boolean catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag) {
+        if ( parentPlatform ==null) {
+            return false;
+        }
+        sendCatalogResponse(channels, parentPlatform, sn, fromTag, 0);
+        return true;
+    }
+    private String getCatalogXml(DeviceChannel channel, String sn, ParentPlatform parentPlatform, int size) {
+        String characterSet = parentPlatform.getCharacterSet();
+        StringBuffer catalogXml = new StringBuffer(600);
+        catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet +"\"?>\r\n");
+        catalogXml.append("<Response>\r\n");
+        catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
+        catalogXml.append("<SN>" +sn + "</SN>\r\n");
+        catalogXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n");
+        catalogXml.append("<SumNum>" + size + "</SumNum>\r\n");
+        catalogXml.append("<DeviceList Num=\"1\">\r\n");
+        catalogXml.append("<Item>\r\n");
+        if (channel != null) {
+            catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
+            catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
+            catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
+            catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
+            catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n");
+            catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
+            catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
+            catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
+            if (channel.getParentId() != null) {
+                catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
+            }
+            catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
+            catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
+            catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n");
+            catalogXml.append("<Longitude>" + channel.getLongitude() + "</Longitude>\r\n");
+            catalogXml.append("<Latitude>" + channel.getLatitude() + "</Latitude>\r\n");
+            catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
+            catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
+            catalogXml.append("<Info>\r\n");
+            catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
+            catalogXml.append("</Info>\r\n");
+        }
+
+
+        catalogXml.append("</Item>\r\n");
+        catalogXml.append("</DeviceList>\r\n");
+        catalogXml.append("</Response>\r\n");
+        return catalogXml.toString();
+    }
+
+    private void sendCatalogResponse(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag, int index) {
+        if (index >= channels.size()) {
+            return;
+        }
+        try {
+            DeviceChannel deviceChannel = channels.get(index);
+            String catalogXml = getCatalogXml(deviceChannel, sn, parentPlatform, channels.size());
+            // callid
+            CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
+                    : udpSipProvider.getNewCallId();
+
+            Request request = headerProviderPlarformProvider.createMessageRequest(parentPlatform, catalogXml, fromTag, callIdHeader);
+            transmitRequest(parentPlatform, request, null, eventResult -> {
+                int indexNext = index + 1;
+                sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext);
+            });
+        } catch (SipException | ParseException | InvalidArgumentException e) {
+            e.printStackTrace();
+        }
     }
 
     /**
@@ -351,7 +385,7 @@
         if (parentPlatform == null) {
             return false;
         }
-
+        logger.info("[鍙戦�� 绉诲姩浣嶇疆璁㈤槄] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat());
         try {
             String characterSet = parentPlatform.getCharacterSet();
             StringBuffer deviceStatusXml = new StringBuffer(600);
@@ -371,7 +405,7 @@
             CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
                     : udpSipProvider.getNewCallId();
             callIdHeader.setCallId(subscribeInfo.getCallId());
-            logger.info("[鍙戦�丯otify-MobilePosition] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat());
+
             sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> {
                 logger.error("鍙戦�丯OTIFY閫氱煡娑堟伅澶辫触銆傞敊璇細{} {}", eventResult.statusCode, eventResult.msg);
             }, null);
@@ -425,7 +459,7 @@
  		// 璁剧疆缂栫爜锛� 闃叉涓枃涔辩爜
 		messageFactory.setDefaultContentEncodingCharset(characterSet);
         Dialog dialog  = subscribeInfo.getDialog();
-        if (dialog == null) return;
+        if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) return;
         SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY);
         ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
         notifyRequest.setContent(catalogXmlContent, contentTypeHeader);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
index 680be66..420f899 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -147,7 +147,7 @@
 			} else {
 				mobilePosition.setAltitude(0.0);
 			}
-			logger.info("[鏀跺埌Notify-MobilePosition]锛歿}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
+			logger.info("[鏀跺埌 绉诲姩浣嶇疆璁㈤槄]锛歿}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
 					mobilePosition.getLongitude(), mobilePosition.getLatitude());
 			mobilePosition.setReportSource("Mobile Position");
 			// 榛樿鏉ユ簮鍧愭爣绯讳负WGS-84澶勭悊
@@ -283,7 +283,7 @@
 					Element eventElement = itemDevice.element("Event");
 					DeviceChannel channel = XmlUtil.channelContentHander(itemDevice);
 					channel.setDeviceId(device.getDeviceId());
-					logger.info("[鏀跺埌Notify-Catalog]锛歿}/{}", device.getDeviceId(), channel.getChannelId());
+					logger.info("[鏀跺埌 鐩綍璁㈤槄]锛歿}/{}", device.getDeviceId(), channel.getChannelId());
 					switch (eventElement.getText().toUpperCase()) {
 						case CatalogEvent.ON: // 涓婄嚎
 							logger.info("鏀跺埌鏉ヨ嚜璁惧銆恵}銆戠殑閫氶亾銆恵}銆戜笂绾块�氱煡", device.getDeviceId(), channel.getChannelId());
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
index 1336705..da1088a 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
@@ -137,6 +137,9 @@
 		String deviceID = XmlUtil.getText(rootElement, "DeviceID");
 		ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
 		SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
+		if (platform == null) {
+			return;
+		}
 		if (evt.getServerTransaction() == null) {
 			ServerTransaction serverTransaction = platform.getTransport().equals("TCP") ? tcpSipProvider.getNewServerTransaction(evt.getRequest())
 					: udpSipProvider.getNewServerTransaction(evt.getRequest());
@@ -146,8 +149,7 @@
 			subscribeInfo.setDialog(dialog);
 		}
 		String sn = XmlUtil.getText(rootElement, "SN");
-		String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() +  "_MobilePosition_" + platformId;
-		logger.info("[notify-MobilePosition]: {}", platformId);
+		logger.info("[鍥炲 绉诲姩浣嶇疆璁㈤槄]: {}", platformId);
 		StringBuilder resultXml = new StringBuilder(200);
 		resultXml.append("<?xml version=\"1.0\" ?>\r\n")
 				.append("<Response>\r\n")
@@ -158,14 +160,25 @@
 				.append("</Response>\r\n");
 
 		if (subscribeInfo.getExpires() > 0) {
-			if (subscribeHolder.getMobilePositionSubscribe(platformId) != null) {
-				dynamicTask.stop(key);
-			}
 			String interval = XmlUtil.getText(rootElement, "Interval"); // GPS涓婃姤鏃堕棿闂撮殧
-			dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager,  platformId, sn, key, subscribeHolder), Integer.parseInt(interval) -1 );
+			if (interval == null) {
+				subscribeInfo.setGpsInterval(5);
+			}else {
+				subscribeInfo.setGpsInterval(Integer.parseInt(interval));
+			}
+
+			subscribeInfo.setSn(sn);
 			subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
+//			if (subscribeHolder.getMobilePositionSubscribe(platformId) == null ) {
+//				subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
+//			}else {
+//				if (subscribeHolder.getMobilePositionSubscribe(platformId).getDialog() != null
+//						&& subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState() != null
+//						&& !subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState().equals(DialogState.CONFIRMED)) {
+//					subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
+//				}
+//			}
 		}else if (subscribeInfo.getExpires() == 0) {
-			dynamicTask.stop(key);
 			subscribeHolder.removeMobilePositionSubscribe(platformId);
 		}
 
@@ -199,8 +212,7 @@
 			subscribeInfo.setDialog(dialog);
 		}
 		String sn = XmlUtil.getText(rootElement, "SN");
-		String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() +  "_Catalog_" + platformId;
-		logger.info("[notify-Catalog]: {}", platformId);
+		logger.info("[鍥炲 鐩綍璁㈤槄]: {}/{}", platformId, deviceID);
 		StringBuilder resultXml = new StringBuilder(200);
 		resultXml.append("<?xml version=\"1.0\" ?>\r\n")
 				.append("<Response>\r\n")
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
index 4f1249a..136b912 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
@@ -12,6 +12,7 @@
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import gov.nist.javax.sip.message.SIPRequest;
 import org.dom4j.DocumentException;
 import org.dom4j.Element;
 import org.slf4j.Logger;
@@ -23,6 +24,7 @@
 import javax.sip.InvalidArgumentException;
 import javax.sip.RequestEvent;
 import javax.sip.SipException;
+import javax.sip.address.SipURI;
 import javax.sip.header.CSeqHeader;
 import javax.sip.header.CallIdHeader;
 import javax.sip.message.Response;
@@ -81,6 +83,17 @@
         // 鏌ヨ涓婄骇骞冲彴鏄惁瀛樺湪
         ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
         try {
+            if (device != null && parentPlatform != null) {
+                logger.warn("[閲嶅]骞冲彴涓庤澶囩紪鍙烽噸澶嶏細{}", deviceId);
+                SIPRequest request = (SIPRequest) evt.getRequest();
+                String hostAddress = request.getRemoteAddress().getHostAddress();
+                int remotePort = request.getRemotePort();
+                if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) {
+                    parentPlatform = null;
+                }else {
+                    device = null;
+                }
+            }
             if (device == null && parentPlatform == null) {
                 // 涓嶅瓨鍦ㄥ垯鍥炲404
                 responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found");
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
index 770d2f7..129f5df 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
@@ -23,6 +23,7 @@
 import javax.sip.address.SipURI;
 import javax.sip.header.HeaderAddress;
 import javax.sip.header.ToHeader;
+import javax.sip.message.Response;
 import java.text.ParseException;
 import java.util.Iterator;
 
@@ -103,6 +104,18 @@
         if (!StringUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) {
             String cmdString = getText(rootElement,"PTZCmd");
             Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
+            if (deviceForPlatform == null) {
+                try {
+                    responseAck(evt, Response.NOT_FOUND);
+                    return;
+                } catch (SipException e) {
+                    e.printStackTrace();
+                } catch (InvalidArgumentException e) {
+                    e.printStackTrace();
+                } catch (ParseException e) {
+                    e.printStackTrace();
+                }
+            }
             cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> {
                 // 澶辫触鐨勫洖澶�
                 try {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
index fc7e233..419a5c2 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
@@ -18,6 +18,7 @@
 import javax.sip.header.FromHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
+import java.util.ArrayList;
 import java.util.List;
 
 @Component
@@ -58,7 +59,8 @@
             List<DeviceChannelInPlatform> deviceChannels = storage.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
             // 鏌ヨ鍏宠仈鐨勭洿鎾�氶亾
             List<GbStream> gbStreams = storage.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
-            int size = deviceChannels.size() + gbStreams.size();
+
+            List<DeviceChannel> allChannels = new ArrayList<>();
             // 鍥炲鐩綍淇℃伅
             List<PlatformCatalog> catalogs =  storage.queryCatalogInPlatform(parentPlatform.getServerGBId());
             if (catalogs.size() > 0) {
@@ -81,9 +83,7 @@
                     deviceChannel.setModel("live");
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setSecrecy("0");
-                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
-                    // 闃叉鍙戦�佽繃蹇�
-                    Thread.sleep(100);
+                    allChannels.add(deviceChannel);
                 }
             }
             // 鍥炲绾ц仈鐨勯�氶亾
@@ -96,9 +96,7 @@
                     deviceChannel.setParental(0);
                     deviceChannel.setParentId(channel.getCatalogId());
                     deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6));
-                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
-                    // 闃叉鍙戦�佽繃蹇�
-                    Thread.sleep(100);
+                    allChannels.add(deviceChannel);
                 }
             }
             // 鍥炲鐩存挱鐨勯�氶亾
@@ -114,7 +112,8 @@
                     deviceChannel.setLatitude(gbStream.getLatitude());
                     deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                     deviceChannel.setManufacture("wvp-pro");
-                    deviceChannel.setStatus(gbStream.isStatus()?1:0);
+//                    deviceChannel.setStatus(gbStream.isStatus()?1:0);
+                    deviceChannel.setStatus(1);
     				deviceChannel.setParentId(gbStream.getCatalogId());
                     deviceChannel.setRegisterWay(1);
                     deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0,6));
@@ -122,16 +121,16 @@
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setParental(0);
                     deviceChannel.setSecrecy("0");
-                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
-                    // 闃叉鍙戦�佽繃蹇�
-                    Thread.sleep(100);
+                    allChannels.add(deviceChannel);
                 }
             }
-            if (size == 0) {
+            if (allChannels.size() > 0) {
+                cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag());
+            }else {
                 // 鍥炲鏃犻�氶亾
-                cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size);
+                cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), 0);
             }
-        } catch (SipException | InvalidArgumentException | ParseException | InterruptedException e) {
+        } catch (SipException | InvalidArgumentException | ParseException e) {
             e.printStackTrace();
         }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
index a953bd9..6a33da4 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
@@ -22,6 +22,7 @@
 import javax.sip.header.FromHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
+import java.util.ArrayList;
 import java.util.List;
 
 @Component
@@ -44,6 +45,9 @@
 
     @Autowired
     private EventPublisher publisher;
+
+    @Autowired
+    private IVideoManagerStorage storage;
 
     @Override
     public void afterPropertiesSet() throws Exception {
@@ -71,10 +75,11 @@
             List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
             // 鍥炲鐩綍淇℃伅
             List<PlatformCatalog> catalogs =  storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
-            int size = catalogs.size() + deviceChannelInPlatforms.size() + gbStreams.size();
+
+            List<DeviceChannel> allChannels = new ArrayList<>();
             if (catalogs.size() > 0) {
                 for (PlatformCatalog catalog : catalogs) {
-                    if (catalog.getParentId().equals(parentPlatform.getServerGBId())) {
+                    if (catalog.getParentId().equals(catalog.getPlatformId())) {
                         catalog.setParentId(parentPlatform.getDeviceGBId());
                     }
                     DeviceChannel deviceChannel = new DeviceChannel();
@@ -92,9 +97,7 @@
                     deviceChannel.setModel("live");
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setSecrecy("0");
-                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
-                    // 闃叉鍙戦�佽繃蹇�
-                    Thread.sleep(100);
+                    allChannels.add(deviceChannel);
                 }
             }
             // 鍥炲绾ц仈鐨勯�氶亾
@@ -103,20 +106,18 @@
                     if (channel.getCatalogId().equals(parentPlatform.getServerGBId())) {
                         channel.setCatalogId(parentPlatform.getDeviceGBId());
                     }
-                    DeviceChannel deviceChannel = storager.queryChannel(channel.getDeviceId(), channel.getChannelId());
+                    DeviceChannel deviceChannel = storage.queryChannel(channel.getDeviceId(), channel.getChannelId());
                     deviceChannel.setParental(0);
                     deviceChannel.setParentId(channel.getCatalogId());
                     deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6));
-                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
-                    // 闃叉鍙戦�佽繃蹇�
-                    Thread.sleep(100);
+                    allChannels.add(deviceChannel);
                 }
             }
             // 鍥炲鐩存挱鐨勯�氶亾
             if (gbStreams.size() > 0) {
                 for (GbStream gbStream : gbStreams) {
                     if (gbStream.getCatalogId().equals(parentPlatform.getServerGBId())) {
-                        gbStream.setCatalogId(parentPlatform.getDeviceGBId());
+                        gbStream.setCatalogId(null);
                     }
                     DeviceChannel deviceChannel = new DeviceChannel();
                     deviceChannel.setChannelId(gbStream.getGbId());
@@ -125,7 +126,8 @@
                     deviceChannel.setLatitude(gbStream.getLatitude());
                     deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                     deviceChannel.setManufacture("wvp-pro");
-                    deviceChannel.setStatus(gbStream.isStatus()?1:0);
+//                    deviceChannel.setStatus(gbStream.isStatus()?1:0);
+                    deviceChannel.setStatus(1);
                     deviceChannel.setParentId(gbStream.getCatalogId());
                     deviceChannel.setRegisterWay(1);
                     deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0,6));
@@ -133,23 +135,20 @@
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setParental(0);
                     deviceChannel.setSecrecy("0");
-
-                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
-                    // 闃叉鍙戦�佽繃蹇�
-                    Thread.sleep(100);
+                    allChannels.add(deviceChannel);
                 }
             }
-            if (size == 0) {
+            if (allChannels.size() > 0) {
+                cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag());
+            }else {
                 // 鍥炲鏃犻�氶亾
-                cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size);
+                cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), 0);
             }
         } catch (SipException e) {
             e.printStackTrace();
         } catch (InvalidArgumentException e) {
             e.printStackTrace();
         } catch (ParseException e) {
-            e.printStackTrace();
-        } catch (InterruptedException e) {
             e.printStackTrace();
         }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
index b8faf63..aae3515 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
@@ -116,16 +116,15 @@
                             continue;
                         }
                         //by brewswang
-                        if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//濡傛灉鍖呭惈浣嶇疆淇℃伅锛屽氨鏇存柊涓�涓嬩綅缃�
-                            processNotifyMobilePosition(evt, itemDevice);
-                        }
-                        
+//                        if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//濡傛灉鍖呭惈浣嶇疆淇℃伅锛屽氨鏇存柊涓�涓嬩綅缃�
+//                            processNotifyMobilePosition(evt, itemDevice);
+//                        }
                         DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice);
                         deviceChannel.setDeviceId(device.getDeviceId());
-                        logger.debug("鏀跺埌鏉ヨ嚜璁惧銆恵}銆戠殑閫氶亾: {}銆恵}銆�", device.getDeviceId(), deviceChannel.getName(), deviceChannel.getChannelId());
+
                         channelList.add(deviceChannel);
                     }
-
+                    logger.info("鏀跺埌鏉ヨ嚜璁惧銆恵}銆戠殑閫氶亾: {}涓紝{}/{}", device.getDeviceId(), channelList.size(), catalogDataCatch.get(key) == null ? 0 :catalogDataCatch.get(key).size(), sumNum);
                     catalogDataCatch.put(key, sumNum, device, channelList);
                     if (catalogDataCatch.get(key).size() == sumNum) {
                         // 鏁版嵁宸茬粡瀹屾暣鎺ユ敹
@@ -147,9 +146,6 @@
                 }
                 // 鍥炲200 OK
                 responseAck(evt, Response.OK);
-                if (offLineDetector.isOnline(device.getDeviceId())) {
-                    publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
-                }
             }
         } catch (DocumentException e) {
             e.printStackTrace();
@@ -231,4 +227,23 @@
             e.printStackTrace();
         }
     }
+
+    public SyncStatus getChannelSyncProgress(String deviceId) {
+        String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;
+        if (catalogDataCatch.get(key) == null) {
+            return null;
+        }else {
+            return catalogDataCatch.getSyncStatus(key);
+        }
+    }
+
+    public void setChannelSyncReady(String deviceId) {
+        String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;
+        catalogDataCatch.addReady(key);
+    }
+
+    public void setChannelSyncEnd(String deviceId, String errorMsg) {
+        String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;
+        catalogDataCatch.setChannelSyncEnd(key, errorMsg);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
index 94ea4e3..7f62968 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -396,7 +396,7 @@
 								}
 							}
 							if (gbStreams.size() > 0) {
-								eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON);
+//								eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON);
 							}
 
 						}else {
@@ -408,7 +408,7 @@
 							}
 							GbStream gbStream = storager.getGbStream(app, streamId);
 							if (gbStream != null) {
-								eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
+//								eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
 							}
 							zlmMediaListManager.removeMedia(app, streamId);
 						}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
index 579842d..9fd4f39 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
@@ -204,6 +204,7 @@
         if (streamProxyItem == null) {
             result = storager.removeMedia(app, streamId);
         }else {
+            // TODO 鏆備笉璁剧疆涓虹绾�
             result =storager.mediaOutline(app, streamId);
         }
         return result;
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
index 68a2af3..17cf7f4 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.service;
 
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
 
 /**
  * 璁惧鐩稿叧涓氬姟澶勭悊
@@ -34,4 +35,24 @@
      * @return
      */
     boolean removeMobilePositionSubscribe(Device device);
+
+    /**
+     * 绉婚櫎绉诲姩浣嶇疆璁㈤槄
+     * @param deviceId 璁惧ID
+     * @return
+     */
+    SyncStatus getChannelSyncStatus(String deviceId);
+
+    /**
+     * 璁剧疆閫氶亾鍚屾鐘舵��
+     * @param deviceId 璁惧ID
+     */
+    void setChannelSyncReady(String deviceId);
+
+    /**
+     * 璁剧疆鍚屾缁撴潫
+     * @param deviceId 璁惧ID
+     * @param errorMsg 閿欒淇℃伅
+     */
+    void setChannelSyncEnd(String deviceId, String errorMsg);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
index e9f7968..d343286 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -3,13 +3,18 @@
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
 import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
+import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+
+import javax.sip.DialogState;
 
 /**
  * 璁惧涓氬姟锛堢洰褰曡闃咃級
@@ -25,24 +30,28 @@
     @Autowired
     private ISIPCommander sipCommander;
 
+    @Autowired
+    private CatalogResponseMessageHandler catalogResponseMessageHandler;
+
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
     @Override
     public boolean addCatalogSubscribe(Device device) {
         if (device == null || device.getSubscribeCycleForCatalog() < 0) {
             return false;
         }
-        if (dynamicTask.contains(device.getDeviceId() + "catalog")) {
-            // 瀛樺湪鍒欏仠姝㈢幇鏈夌殑锛屽紑鍚柊鐨�
-            dynamicTask.stop(device.getDeviceId() + "catalog");
+        CatalogSubscribeTask task = (CatalogSubscribeTask)dynamicTask.get(device.getDeviceId() + "catalog");
+        if (task != null && task.getDialogState() != null && task.getDialogState().equals(DialogState.CONFIRMED)) { // 宸插瓨鍦ㄤ笉闇�瑕佸啀娆℃坊鍔�
+            return true;
         }
         logger.info("[娣诲姞鐩綍璁㈤槄] 璁惧{}", device.getDeviceId());
         // 娣诲姞鐩綍璁㈤槄
         CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander);
-        catalogSubscribeTask.run();
         // 鎻愬墠寮�濮嬪埛鏂拌闃�
-        int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog();
+        int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30);
         // 璁剧疆鏈�灏忓�间负30
-        subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30);
-        dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog);
+        dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog -1);
         return true;
     }
 
@@ -61,18 +70,16 @@
         if (device == null || device.getSubscribeCycleForMobilePosition() < 0) {
             return false;
         }
-        if (dynamicTask.contains(device.getDeviceId() + "mobile_position")) {
-            // 瀛樺湪鍒欏仠姝㈢幇鏈夌殑锛屽紑鍚柊鐨�
-            dynamicTask.stop(device.getDeviceId() + "mobile_position");
-        }
         logger.info("[娣诲姞绉诲姩浣嶇疆璁㈤槄] 璁惧{}", device.getDeviceId());
+        MobilePositionSubscribeTask task = (MobilePositionSubscribeTask)dynamicTask.get(device.getDeviceId() + "mobile_position");
+        if (task != null &&  task.getDialogState() != null && task.getDialogState().equals(DialogState.CONFIRMED)) { // 宸插瓨鍦ㄤ笉闇�瑕佸啀娆℃坊鍔�
+            return true;
+        }
         // 娣诲姞鐩綍璁㈤槄
         MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander);
-        mobilePositionSubscribeTask.run();
         // 鎻愬墠寮�濮嬪埛鏂拌闃�
-        int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog();
         // 璁剧疆鏈�灏忓�间负30
-        subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30);
+        int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30);
         dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog -1 );
         return true;
     }
@@ -86,4 +93,19 @@
         dynamicTask.stop(device.getDeviceId() + "mobile_position");
         return true;
     }
+
+    @Override
+    public SyncStatus getChannelSyncStatus(String deviceId) {
+        return catalogResponseMessageHandler.getChannelSyncProgress(deviceId);
+    }
+
+    @Override
+    public void setChannelSyncReady(String deviceId) {
+        catalogResponseMessageHandler.setChannelSyncReady(deviceId);
+    }
+
+    @Override
+    public void setChannelSyncEnd(String deviceId, String errorMsg) {
+        catalogResponseMessageHandler.setChannelSyncEnd(deviceId, errorMsg);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
index 3f8c493..bbf992f 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
@@ -100,7 +100,8 @@
         deviceChannel.setLatitude(gbStream.getLatitude());
         deviceChannel.setDeviceId(deviceGBId);
         deviceChannel.setManufacture("wvp-pro");
-        deviceChannel.setStatus(gbStream.isStatus()?1:0);
+//        deviceChannel.setStatus(gbStream.isStatus()?1:0);
+        deviceChannel.setStatus(1);
         deviceChannel.setParentId(catalogId ==null?gbStream.getCatalogId():catalogId);
         deviceChannel.setRegisterWay(1);
         deviceChannel.setCivilCode(deviceGBId.substring(0, 6));
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
index e66dfa0..c6b7e64 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -216,4 +216,5 @@
     void sendMobilePositionMsg(JSONObject jsonObject);
 
     void sendStreamPushRequestedMsg(MessageForPushChannel messageForPushChannel);
+
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
index 1fb7fd0..fc78de4 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -638,4 +638,5 @@
         logger.info("[redis 鎺ㄦ祦琚姹傞�氱煡] {}: {}-{}", key, msg.getApp(), msg.getStream());
         redis.convertAndSend(key, (JSONObject)JSON.toJSON(msg));
     }
+
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
index 667a619..20e56d9 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -445,8 +445,6 @@
 		device.setOnline(1);
 		logger.info("鏇存柊璁惧鍦ㄧ嚎: " + deviceId);
 		redisCatchStorage.updateDevice(device);
-		List<DeviceChannel> deviceChannelList = deviceChannelMapper.queryOnlineChannelsByDeviceId(deviceId);
-		eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON);
 		return deviceMapper.update(device) > 0;
 	}
 
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java b/src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java
new file mode 100644
index 0000000..c10357c
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java
@@ -0,0 +1,126 @@
+package com.genersoft.iot.vmp.utils;
+
+/**
+ * 鍧愭爣杞崲
+ * 涓�涓彁渚涗簡鐧惧害鍧愭爣锛圔D09锛夈�佸浗娴嬪眬鍧愭爣锛堢伀鏄熷潗鏍囷紝GCJ02锛夈�佸拰WGS84鍧愭爣绯讳箣闂寸殑杞崲鐨勫伐鍏风被
+ * 鍙傝�僪ttps://github.com/wandergis/coordtransform 鍐欑殑Java鐗堟湰
+ * @author Xinconan
+ * @date 2016-03-18
+ * @url https://github.com/xinconan/coordtransform
+ */
+public class Coordtransform {
+
+	private static double x_PI = 3.14159265358979324 * 3000.0 / 180.0;
+	private static double PI = 3.1415926535897932384626;
+	private static double a = 6378245.0;
+	private static double ee = 0.00669342162296594323;
+	
+	/**
+	 * 鐧惧害鍧愭爣绯� (BD-09) 涓� 鐏槦鍧愭爣绯� (GCJ-02)鐨勮浆鎹�
+     * 鍗� 鐧惧害 杞� 璋锋瓕銆侀珮寰�
+	 * @param bd_lon
+	 * @param bd_lat
+	 * @return Double[lon,lat]
+	 */
+	public static Double[] BD09ToGCJ02(Double bd_lon,Double bd_lat){
+		double x = bd_lon - 0.0065;
+		double y = bd_lat - 0.006;
+		double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI);
+		double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI);
+		Double[] arr = new Double[2];
+		arr[0] = z * Math.cos(theta);
+		arr[1] = z * Math.sin(theta);
+		return arr;
+	}
+	
+	/**
+	 * 鐏槦鍧愭爣绯� (GCJ-02) 涓庣櫨搴﹀潗鏍囩郴 (BD-09) 鐨勮浆鎹�
+     * 鍗宠胺姝屻�侀珮寰� 杞� 鐧惧害
+	 * @param gcj_lon
+	 * @param gcj_lat
+	 * @return Double[lon,lat]
+	 */
+	public static Double[] GCJ02ToBD09(Double gcj_lon,Double gcj_lat){
+		double z = Math.sqrt(gcj_lon * gcj_lon + gcj_lat * gcj_lat) + 0.00002 * Math.sin(gcj_lat * x_PI);
+		double theta = Math.atan2(gcj_lat, gcj_lon) + 0.000003 * Math.cos(gcj_lon * x_PI);
+		Double[] arr = new Double[2];
+		arr[0] = z * Math.cos(theta) + 0.0065;
+		arr[1] = z * Math.sin(theta) + 0.006;
+		return arr;
+	}
+	
+	/**
+	 * WGS84杞珿CJ02
+	 * @param wgs_lon
+	 * @param wgs_lat
+	 * @return Double[lon,lat]
+	 */
+	public static Double[] WGS84ToGCJ02(Double wgs_lon,Double wgs_lat){
+		if(outOfChina(wgs_lon, wgs_lat)){
+			return new Double[]{wgs_lon,wgs_lat};
+		}
+		double dlat = transformlat(wgs_lon - 105.0, wgs_lat - 35.0);
+		double dlng = transformlng(wgs_lon - 105.0, wgs_lat - 35.0);
+		double radlat = wgs_lat / 180.0 * PI;
+		double magic = Math.sin(radlat);
+        magic = 1 - ee * magic * magic;
+        double sqrtmagic = Math.sqrt(magic);
+        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
+        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
+        Double[] arr = new Double[2];
+        arr[0] = wgs_lon + dlng;
+        arr[1] = wgs_lat + dlat;
+		return arr;
+	}
+	
+	/**
+	 * GCJ02杞琖GS84
+	 * @param gcj_lon
+	 * @param gcj_lat
+	 * @return Double[lon,lat]
+	 */
+	public static Double[] GCJ02ToWGS84(Double gcj_lon,Double gcj_lat){
+		if(outOfChina(gcj_lon, gcj_lat)){
+			return new Double[]{gcj_lon,gcj_lat};
+		}
+		double dlat = transformlat(gcj_lon - 105.0, gcj_lat - 35.0);
+		double dlng = transformlng(gcj_lon - 105.0, gcj_lat - 35.0);
+		double radlat = gcj_lat / 180.0 * PI;
+		double magic = Math.sin(radlat);
+        magic = 1 - ee * magic * magic;
+        double sqrtmagic = Math.sqrt(magic);
+        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
+        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
+        double mglat = gcj_lat + dlat;
+        double mglng = gcj_lon + dlng;
+        return new Double[]{gcj_lon * 2 - mglng, gcj_lat * 2 - mglat};
+	}
+	
+	private static Double transformlat(double lng, double lat) {
+        double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
+        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
+        ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
+        ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
+        return ret;
+    }
+	
+	private static Double transformlng(double lng,double lat) {
+        double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
+        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
+        ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
+        ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
+        return ret;
+    }
+	
+	/**
+	 * outOfChina
+	 * @鎻忚堪: 鍒ゆ柇鏄惁鍦ㄥ浗鍐咃紝涓嶅湪鍥藉唴鍒欎笉鍋氬亸绉�
+	 * @param lng
+	 * @param lat
+	 * @return {boolean}
+	 */
+	private static boolean outOfChina(Double lng,Double lat) {
+        return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
+    };
+	
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java
index 53e6a61..47f9421 100644
--- a/src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java
+++ b/src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java
@@ -17,48 +17,57 @@
     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) {
-                // logger.info(tmp);
-                json += tmp;
-            }
+//        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) {
+//                // logger.info(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 {
+//                logger.info("gps鍧愭爣鏃犳晥锛侊紒");
+//            }
+//            out.close();
+//            br.close();
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
 
-            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 {
-                logger.info("gps鍧愭爣鏃犳晥锛侊紒");
-            }
-            out.close();
-            br.close();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return null;
+
+        double lng = Double.parseDouble(xx);
+        double lat = Double.parseDouble(yy);
+        Double[] gcj02 = Coordtransform.WGS84ToGCJ02(lng, lat);
+        Double[] doubles = Coordtransform.GCJ02ToBD09(gcj02[0], gcj02[1]);
+        BaiduPoint bdPoint= new BaiduPoint();
+        bdPoint.setBdLng(doubles[0] + "");
+        bdPoint.setBdLat(doubles[1] + "");
+        return bdPoint;
     }
 
     /**
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
index 5e9cd60..12136f4 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -4,7 +4,13 @@
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
+import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
 import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
+import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
+import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
+import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;
+import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
 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;
@@ -18,6 +24,7 @@
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
+import org.kxml2.wap.wv.WV;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -27,9 +34,8 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
+import javax.sip.DialogState;
+import java.util.*;
 
 @Api(tags = "鍥芥爣璁惧鏌ヨ", value = "鍥芥爣璁惧鏌ヨ")
 @SuppressWarnings("rawtypes")
@@ -60,6 +66,9 @@
 
 	@Autowired
 	private DynamicTask dynamicTask;
+
+	@Autowired
+	private SubscribeHolder subscribeHolder;
 
 	/**
 	 * 浣跨敤ID鏌ヨ鍥芥爣璁惧
@@ -149,48 +158,30 @@
 			@ApiImplicitParam(name="deviceId", value = "璁惧id", required = true, dataTypeClass = String.class),
 	})
 	@PostMapping("/devices/{deviceId}/sync")
-	public DeferredResult<ResponseEntity<Device>> devicesSync(@PathVariable String deviceId){
+	public WVPResult<SyncStatus> devicesSync(@PathVariable String deviceId){
 		
 		if (logger.isDebugEnabled()) {
 			logger.debug("璁惧閫氶亾淇℃伅鍚屾API璋冪敤锛宒eviceId锛�" + deviceId);
 		}
 		Device device = storager.queryVideoDevice(deviceId);
-		String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;
-		String uuid = UUID.randomUUID().toString();
-		// 榛樿瓒呮椂鏃堕棿涓�30鍒嗛挓
-		DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(30*60*1000L);
-		result.onTimeout(()->{
-			logger.warn("璁惧[{}]閫氶亾淇℃伅鍚屾瓒呮椂", deviceId);
-			// 閲婃斁rtpserver
-			RequestMessage msg = new RequestMessage();
-			msg.setKey(key);
-			msg.setId(uuid);
-			WVPResult<Object> wvpResult = new WVPResult<>();
-			wvpResult.setCode(-1);
-			wvpResult.setData(device);
-			wvpResult.setMsg("鏇存柊瓒呮椂");
-			msg.setData(wvpResult);
-			resultHolder.invokeAllResult(msg);
-
-		});
-		// 绛夊緟鍏朵粬鐩稿悓璇锋眰杩斿洖鏃朵竴璧疯繑鍥�
-		if (resultHolder.exist(key, null)) {
-			return result;
+		SyncStatus syncStatus = deviceService.getChannelSyncStatus(deviceId);
+		// 宸插瓨鍦ㄥ垯杩斿洖杩涘害
+		if (syncStatus != null && syncStatus.getErrorMsg() == null) {
+			WVPResult<SyncStatus> wvpResult = new WVPResult<>();
+			wvpResult.setCode(0);
+			wvpResult.setData(syncStatus);
+			return wvpResult;
 		}
-        cmder.catalogQuery(device, event -> {
-			RequestMessage msg = new RequestMessage();
-			msg.setKey(key);
-			msg.setId(uuid);
-			WVPResult<Object> wvpResult = new WVPResult<>();
-			wvpResult.setCode(-1);
-			wvpResult.setData(device);
-			wvpResult.setMsg(String.format("鍚屾閫氶亾澶辫触锛岄敊璇爜锛� %s, %s", event.statusCode, event.msg));
-			msg.setData(wvpResult);
-			resultHolder.invokeAllResult(msg);
+		SyncStatus syncStatusReady = new SyncStatus();
+		deviceService.setChannelSyncReady(deviceId);
+		cmder.catalogQuery(device, event -> {
+			String errorMsg = String.format("鍚屾閫氶亾澶辫触锛岄敊璇爜锛� %s, %s", event.statusCode, event.msg);
+			deviceService.setChannelSyncEnd(deviceId, errorMsg);
 		});
-
-        resultHolder.put(key, uuid, result);
-        return result;
+		WVPResult<SyncStatus> wvpResult = new WVPResult<>();
+		wvpResult.setCode(0);
+		wvpResult.setMsg("寮�濮嬪悓姝�");
+		return wvpResult;
 	}
 
 	/**
@@ -467,4 +458,47 @@
 	public WVPResult<List<DeviceChannelTree>> tree(@PathVariable String deviceId) {
 		return WVPResult.Data(storager.tree(deviceId));
 	}
+
+	@GetMapping("/{deviceId}/sync_status")
+	@ApiOperation(value = "鑾峰彇閫氶亾鍚屾杩涘害", notes = "鑾峰彇閫氶亾鍚屾杩涘害")
+	public WVPResult<SyncStatus> getSyncStatus(@PathVariable String deviceId) {
+		SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId);
+		WVPResult<SyncStatus> wvpResult = new WVPResult<>();
+		if (channelSyncStatus == null) {
+			wvpResult.setCode(-1);
+			wvpResult.setMsg("鍚屾灏氭湭寮�濮�");
+		}else {
+			wvpResult.setCode(0);
+			wvpResult.setData(channelSyncStatus);
+			if (channelSyncStatus.getErrorMsg() != null) {
+				wvpResult.setMsg(channelSyncStatus.getErrorMsg());
+			}
+		}
+		return wvpResult;
+	}
+
+	@GetMapping("/{deviceId}/subscribe_info")
+	@ApiOperation(value = "鑾峰彇璁惧鐨勮闃呯姸鎬�", notes = "鑾峰彇璁惧鐨勮闃呯姸鎬�")
+	public WVPResult<Map<String, String>> getSubscribeInfo(@PathVariable String deviceId) {
+		Set<String> allKeys = dynamicTask.getAllKeys();
+		Map<String, String> dialogStateMap = new HashMap<>();
+		for (String key : allKeys) {
+			if (key.startsWith(deviceId)) {
+				ISubscribeTask subscribeTask = (ISubscribeTask)dynamicTask.get(key);
+				DialogState dialogState = subscribeTask.getDialogState();
+				if (dialogState == null) {
+					continue;
+				}
+				if (subscribeTask instanceof CatalogSubscribeTask) {
+					dialogStateMap.put("catalog", dialogState.toString());
+				}else if (subscribeTask instanceof MobilePositionSubscribeTask) {
+					dialogStateMap.put("mobilePosition", dialogState.toString());
+				}
+			}
+		}
+		WVPResult<Map<String, String>> wvpResult = new WVPResult<>();
+		wvpResult.setCode(0);
+		wvpResult.setData(dialogStateMap);
+		return wvpResult;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
index a0e7a73..faed2c8 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
@@ -4,6 +4,7 @@
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.VManageBootstrap;
 import com.genersoft.iot.vmp.common.VersionPo;
+import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.VersionInfo;
@@ -27,6 +28,7 @@
 import javax.sip.SipProvider;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 @SuppressWarnings("rawtypes")
 @Api(tags = "鏈嶅姟鎺у埗")
@@ -42,13 +44,16 @@
     private IMediaServerService mediaServerService;
 
     @Autowired
-    VersionInfo versionInfo;
+    private VersionInfo versionInfo;
 
     @Autowired
-    SipConfig sipConfig;
+    private SipConfig sipConfig;
 
     @Autowired
-    UserSetting userSetting;
+    private UserSetting userSetting;
+
+    @Autowired
+    private DynamicTask dynamicTask;
 
     @Value("${server.port}")
     private int serverPort;
@@ -248,4 +253,35 @@
         result.setData(jsonObject);
         return result;
     }
+
+//    @ApiOperation("褰撳墠杩涜涓殑鍔ㄦ�佷换鍔�")
+//    @GetMapping(value = "/dynamicTask")
+//    @ResponseBody
+//    public WVPResult<JSONObject> getDynamicTask(){
+//        WVPResult<JSONObject> result = new WVPResult<>();
+//        result.setCode(0);
+//        result.setMsg("success");
+//
+//        JSONObject jsonObject = new JSONObject();
+//
+//        Set<String> allKeys = dynamicTask.getAllKeys();
+//        jsonObject.put("server.port", serverPort);
+//        if (StringUtils.isEmpty(type)) {
+//            jsonObject.put("sip", JSON.toJSON(sipConfig));
+//            jsonObject.put("base", JSON.toJSON(userSetting));
+//        }else {
+//            switch (type){
+//                case "sip":
+//                    jsonObject.put("sip", sipConfig);
+//                    break;
+//                case "base":
+//                    jsonObject.put("base", userSetting);
+//                    break;
+//                default:
+//                    break;
+//            }
+//        }
+//        result.setData(jsonObject);
+//        return result;
+//    }
 }
diff --git a/web_src/src/components/DeviceList.vue b/web_src/src/components/DeviceList.vue
index 74e3fbc..4f8b460 100644
--- a/web_src/src/components/DeviceList.vue
+++ b/web_src/src/components/DeviceList.vue
@@ -57,7 +57,7 @@
 
 					<el-table-column label="鎿嶄綔" width="450" align="center" fixed="right">
 						<template slot-scope="scope">
-							<el-button size="mini" :loading="scope.row.loading"  v-if="scope.row.online!=0" icon="el-icon-refresh"  @click="refDevice(scope.row)">鍒锋柊</el-button>
+              <el-button size="mini" v-if="scope.row.online!=0" icon="el-icon-refresh" @click="refDevice(scope.row)" @mouseover="getTooltipContent(scope.row.deviceId)">鍒锋柊</el-button>
 							<el-button-group>
                 <el-button size="mini" icon="el-icon-video-camera-solid" v-bind:disabled="scope.row.online==0"  type="primary" @click="showChannelList(scope.row)">閫氶亾</el-button>
                 <el-button size="mini" icon="el-icon-location" v-bind:disabled="scope.row.online==0"  type="primary" @click="showDevicePosition(scope.row)">瀹氫綅</el-button>
@@ -78,6 +78,7 @@
 					:total="total">
 				</el-pagination>
         <deviceEdit ref="deviceEdit" ></deviceEdit>
+        <syncChannelProgress ref="syncChannelProgress" ></syncChannelProgress>
 			</el-main>
 		</el-container>
 	</div>
@@ -86,11 +87,13 @@
 <script>
 	import uiHeader from './UiHeader.vue'
 	import deviceEdit from './dialog/deviceEdit.vue'
+	import syncChannelProgress from './dialog/SyncChannelProgress.vue'
 	export default {
 		name: 'app',
 		components: {
 			uiHeader,
-      deviceEdit
+      deviceEdit,
+      syncChannelProgress,
 		},
 		data() {
 			return {
@@ -104,7 +107,7 @@
 				currentPage:1,
 				count:15,
 				total:0,
-				getDeviceListLoading: false
+				getDeviceListLoading: false,
 			};
 		},
 		computed: {
@@ -117,8 +120,6 @@
 					});
 					this.currentDeviceChannelsLenth = channels.length;
 				}
-
-				console.log("鏁版嵁锛�" + JSON.stringify(channels));
 				return channels;
 			}
 		},
@@ -153,13 +154,11 @@
 						count: that.count
 					}
 				}).then(function (res) {
-					console.log(res);
-					console.log(res.data.list);
 					that.total = res.data.total;
 					that.deviceList = res.data.list;
 					that.getDeviceListLoading = false;
 				}).catch(function (error) {
-					console.log(error);
+					console.error(error);
 					that.getDeviceListLoading = false;
 				});
 
@@ -182,7 +181,7 @@
           }).then((res)=>{
             this.getDeviceList();
           }).catch((error) =>{
-            console.log(error);
+            console.error(error);
           });
         }).catch(() => {
 
@@ -191,11 +190,9 @@
 
 			},
 			showChannelList: function(row) {
-				console.log(JSON.stringify(row))
 				this.$router.push(`/channelList/${row.deviceId}/0/15/1`);
 			},
 			showDevicePosition: function(row) {
-				console.log(JSON.stringify(row))
 				this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`);
 			},
 
@@ -203,12 +200,11 @@
 			//鍒锋柊璁惧淇℃伅
 			refDevice: function(itemData) {
 				console.log("鍒锋柊瀵瑰簲璁惧:" + itemData.deviceId);
-				var that = this;
-        that.$set(itemData,"loading", true);
+				let that = this;
 				this.$axios({
 					method: 'post',
 					url: '/api/device/query/devices/' + itemData.deviceId + '/sync'
-				}).then(function(res) {
+				}).then((res) => {
 					console.log("鍒锋柊璁惧缁撴灉锛�"+JSON.stringify(res));
 					if (res.data.code !==0) {
 						that.$message({
@@ -217,24 +213,44 @@
 							type: 'error'
 						});
 					}else{
-						that.$message({
-							showClose: true,
-							message: res.data.msg,
-							type: 'success'
-						});
+						// that.$message({
+						// 	showClose: true,
+						// 	message: res.data.msg,
+						// 	type: 'success'
+						// });
+            this.$refs.syncChannelProgress.openDialog(itemData.deviceId)
 					}
 					that.initData()
-          that.$set(itemData,"loading", true);
-				}).catch(function(e) {
+				}).catch((e) => {
 					console.error(e)
           that.$message({
             showClose: true,
             message: e,
             type: 'error'
           });
-          that.$set(itemData,"loading", true);
 				});
+
 			},
+
+      getTooltipContent: async function (deviceId){
+         let result = "";
+         await this.$axios({
+            method: 'get',
+            async: false,
+            url:`/api/device/query/${deviceId}/sync_status/`,
+          }).then((res) => {
+           if (res.data.code == 0) {
+             if (res.data.data.errorMsg !== null) {
+               result = res.data.data.errorMsg
+             } else if (res.data.msg !== null) {
+               result = res.data.msg
+             } else {
+               result = `鍚屾涓�...[${res.data.data.current}/${res.data.data.total}]`;
+             }
+           }
+         })
+         return result;
+      },
 			//閫氱煡璁惧涓婁紶濯掍綋娴�
 			sendDevicePush: function(itemData) {
 				// let deviceId = this.currentDevice.deviceId;
@@ -251,7 +267,6 @@
 				// });
 			},
       transportChange: function (row) {
-        console.log(row);
         console.log(`淇敼浼犺緭鏂瑰紡涓� ${row.streamMode}锛�${row.deviceId} `);
         let that = this;
         this.$axios({
@@ -263,7 +278,6 @@
         });
       },
       edit: function (row) {
-        console.log(row);
         this.$refs.deviceEdit.openDialog(row, ()=>{
           this.$refs.deviceEdit.close();
           this.$message({
diff --git a/web_src/src/components/dialog/SyncChannelProgress.vue b/web_src/src/components/dialog/SyncChannelProgress.vue
new file mode 100644
index 0000000..1ec16f4
--- /dev/null
+++ b/web_src/src/components/dialog/SyncChannelProgress.vue
@@ -0,0 +1,102 @@
+<template>
+  <div id="SyncChannelProgress" v-loading="isLoging">
+    <el-dialog
+      width="240px"
+      top="13%"
+      :append-to-body="true"
+      :close-on-click-modal="false"
+      :visible.sync="showDialog"
+      :destroy-on-close="true"
+      :show-close="true"
+      @close="close()"
+     style="text-align: center">
+      <el-progress type="circle" :percentage="percentage" :status="syncStatus"></el-progress>
+      <div style="text-align: center">
+        {{msg}}
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: "SyncChannelProgress",
+  computed: {},
+  props: ['platformId'],
+  created() {},
+  data() {
+    return {
+      syncStatus: null,
+      percentage: 0,
+      total: 0,
+      current: 0,
+      showDialog: false,
+      isLoging: false,
+      syncFlag: false,
+      deviceId: null,
+      timmer: null,
+      msg: "姝e湪鍚屾",
+    };
+  },
+  methods: {
+    openDialog: function (deviceId) {
+      console.log("deviceId: " + deviceId)
+      this.deviceId = deviceId;
+      this.showDialog = true;
+      this.msg = "";
+      this.percentage= 0;
+      this.total= 0;
+      this.current= 0;
+      this.syncFlag= false;
+      this.syncStatus = null;
+      this.getProgress()
+    },
+    getProgress(){
+      this.$axios({
+        method: 'get',
+        url:`/api/device/query/${this.deviceId}/sync_status/`,
+      }).then((res) => {
+        if (res.data.code == 0) {
+          if (!this.syncFlag) {
+            this.syncFlag = true;
+          }
+          if (res.data.data == null) {
+            this.syncStatus = "success"
+            this.percentage = 100;
+            this.msg = '鍚屾鎴愬姛';
+          }else if (res.data.data.total == 0){
+            this.msg = `绛夊緟鍚屾涓璥;
+            this.timmer = setTimeout(this.getProgress, 300)
+          }else if (res.data.data.errorMsg !== null ){
+            this.msg = res.data.data.errorMsg;
+            this.syncStatus = "exception"
+          }else {
+            this.total = res.data.data.total;
+            this.current = res.data.data.current;
+            this.percentage = Math.floor(Number(res.data.data.current)/Number(res.data.data.total)* 10000)/100;
+            this.msg = `鍚屾涓�...[${res.data.data.current}/${res.data.data.total}]`;
+            this.timmer = setTimeout(this.getProgress, 300)
+          }
+        }else {
+          if (this.syncFlag) {
+            this.syncStatus = "success"
+            this.percentage = 100;
+            this.msg = '鍚屾鎴愬姛';
+          }else {
+            this.syncStatus = "error"
+            this.msg = res.data.msg;
+          }
+        }
+      }).catch((error) =>{
+        console.log(error);
+        this.syncStatus = "error"
+        this.msg = error.response.data.msg;
+      });
+    },
+    close: function (){
+      window.clearTimeout(this.timmer)
+    }
+  },
+};
+</script>

--
Gitblit v1.8.0