From c46935ce6c9fb2aab589f03e7adf362a5e18ade2 Mon Sep 17 00:00:00 2001
From: scolGit <943953050@qq.com>
Date: Mon, 17 May 2021 15:19:49 +0800
Subject: [PATCH] 流域监控功能提交

---
 backend/inz.common/src/main/java/com/beecode/inz/common/enumeration/GpsooErrorCodeEnum.java                  |  53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 backend/inz.common/src/main/java/com/beecode/inz/common/util/GpsOOUtil.java                                  | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 backend/inz.common/src/main/java/com/beecode/inz/common/util/HttpSendUtil.java                               | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/SandMiningAreaDao.java                           |   6 ++++++
 backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/ShipInfoDao.java                                 |   2 ++
 backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/dao/ShipInfoDaoImpl.java                    |  32 +++++++++++++++++++++++---------
 backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/SandMiningAreaServiceImpl.java      |   5 +++++
 backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/ShipInfoServiceImpl.java            |  53 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/SandMiningAreaService.java                   |   3 +++
 backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/ShipInfoService.java                         |   9 +++++++++
 backend/xyst.dinas.camera/build.gradle                                                                       |   2 +-
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/config/CameraPlayConfiguration.java            |   5 +++++
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/dao/CameraInfoDao.java                         |   2 ++
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/RegionalCompanyWatershedCameraTree.java |  35 +++++++++++++++++++++++++++++++++++
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/WatershedCameraTree.java                |  36 ++++++++++++++++++++++++++++++++++++
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/dao/CameraInfoDaoImpl.java            |  41 +++++++++++++++++++++++++++++------------
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/service/CameraInfoServiceImpl.java    |  70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/service/CameraInfoService.java                 |   4 ++++
 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/web/WatershedCameraPlayController.java         |  76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 19 files changed, 801 insertions(+), 28 deletions(-)
 create mode 100644 backend/inz.common/src/main/java/com/beecode/inz/common/enumeration/GpsooErrorCodeEnum.java
 create mode 100644 backend/inz.common/src/main/java/com/beecode/inz/common/util/GpsOOUtil.java
 create mode 100644 backend/inz.common/src/main/java/com/beecode/inz/common/util/HttpSendUtil.java
 create mode 100644 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/RegionalCompanyWatershedCameraTree.java
 create mode 100644 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/WatershedCameraTree.java
 create mode 100644 backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/web/WatershedCameraPlayController.java

diff --git a/backend/inz.common/src/main/java/com/beecode/inz/common/enumeration/GpsooErrorCodeEnum.java b/backend/inz.common/src/main/java/com/beecode/inz/common/enumeration/GpsooErrorCodeEnum.java
new file mode 100644
index 0000000..48d8c89
--- /dev/null
+++ b/backend/inz.common/src/main/java/com/beecode/inz/common/enumeration/GpsooErrorCodeEnum.java
@@ -0,0 +1,53 @@
+package com.beecode.inz.common.enumeration;
+
+import java.util.Arrays;
+
+public enum GpsooErrorCodeEnum {
+
+       ERROR_CODE_10001(10001,"系统错误"),
+       ERROR_CODE_10002(10002,"请求的接口不存在"),
+       ERROR_CODE_10003(10003,"请求频率超过上限"),
+       ERROR_CODE_10004(10004,"access_token不存在"),
+       ERROR_CODE_10005(10005,"access_token错误"),
+       ERROR_CODE_10006(10006,"access_token已过期,请重新获取"),
+       ERROR_CODE_20001(20001,"账号或密码错误"),
+       ERROR_CODE_20002(20002,"缺失必选参数(%s),请参考API文档"),
+       ERROR_CODE_20003(20003,"参数(%s)值非法,%s,请参考API文档"),
+       ERROR_CODE_20004(20004,"监控账号不存在"),
+       ERROR_CODE_20005(20005,"无权查看该账号(%s)信息"),
+       ERROR_CODE_20006(20006,"%s账号名下设备数量超过上限"),
+       ERROR_CODE_20007(20007,"IMEI不存在(%s)"),
+       ERROR_CODE_20008(20008,"无权查看该设备(%s)信息"),
+       ERROR_CODE_20009(20009,"请求的设备数量超过上限"),
+       ERROR_CODE_20010(20010,"该设备已过期(%s)"),
+       ERROR_CODE_20011(20011,"地图类型错误,请参考API文档"),
+       ERROR_CODE_20012(20012,"非法经纬度");
+
+     private int code;
+     private String message;
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    GpsooErrorCodeEnum(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public static String getMessageByCode(int code){
+        return Arrays.stream(GpsooErrorCodeEnum.values()).filter(gpsooErrorCodeEnum -> gpsooErrorCodeEnum.code==code).findFirst().get().message;
+    }
+}
diff --git a/backend/inz.common/src/main/java/com/beecode/inz/common/util/GpsOOUtil.java b/backend/inz.common/src/main/java/com/beecode/inz/common/util/GpsOOUtil.java
new file mode 100644
index 0000000..537fab0
--- /dev/null
+++ b/backend/inz.common/src/main/java/com/beecode/inz/common/util/GpsOOUtil.java
@@ -0,0 +1,230 @@
+package com.beecode.inz.common.util;
+
+import org.apache.commons.lang.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 汽车在线OPEN API http://gpsoo.net/open/v1.0/dataApi.html#block-3.1
+ */
+public class GpsOOUtil {
+
+    private static Logger logger = LoggerFactory.getLogger(GpsOOUtil.class);
+
+
+    public static String getGpsooTokenRedisKey(String account, String password) {
+        return "gpsoo_token_key" + account + "_" + password;
+    }
+
+    public static String getGpsooImeisTrackingRedisKey(String account, String password,String imeis,String mapType) {
+        return "gpsoo_imeis_tracking_key" + account + "_" + password+"_"+imeis+"_"+mapType;
+    }
+
+    private static final String GPSOO_DOMAIN = "https://api.gpsoo.net/";
+    private static final String GPSOO_DOMAIN_BASE_URL =GPSOO_DOMAIN+ "1/";
+    /**
+     * 获取tokenUrl
+     */
+    private static final String TOKEN_URL =  GPSOO_DOMAIN_BASE_URL +"auth/access_token";
+    /**
+     * 监控URL
+     */
+    private static final String MONITOR_URL =  GPSOO_DOMAIN_BASE_URL +"account/monitor";
+    /**
+     * 跟踪URL
+     */
+    private static final String TRACKING_URL =  GPSOO_DOMAIN_BASE_URL +"devices/tracking";
+    /**
+     * 历史轨迹URL
+     */
+    private static final String HISTORY_URL =  GPSOO_DOMAIN_BASE_URL +"devices/history";
+
+
+    /**
+     * 获取TOKEN
+     * @param account
+     * @param password
+     * @return
+     * @throws Exception
+     */
+    public static String getTokenByAccount(String account ,String password) throws Exception {
+        if(StringUtils.isEmpty(account)|| StringUtils.isEmpty(password)){
+            return null;
+        }
+        String token = RedisUtils.getInstance().get(getGpsooTokenRedisKey(account, password));
+        if(StringUtils.isNotEmpty(token)){
+            return token;
+        }
+        String accountEncode = URLEncoder.encode(account, StandardCharsets.UTF_8.name());
+        String passwordEncode = URLEncoder.encode(password, StandardCharsets.UTF_8.name());
+        String time = Long.toString(System.currentTimeMillis()/1000L);
+        String encryption1 = Digests.md5encryption(Digests.md5encryption(passwordEncode) + time);
+        String sendParam = "account=" + accountEncode + "&time=" + time+"&signature="+encryption1;
+        String sendPost = HttpSendUtil.sendPost(TOKEN_URL, sendParam, StandardCharsets.UTF_8.name());
+        JSONObject postStr = new JSONObject(sendPost);
+        Integer ret = postStr.getInt("ret");
+        if (0==ret) {
+            String accessToken = postStr.getString("access_token");
+            //去掉三秒的缓存
+            if(postStr.getInt("expires_in")-3<0){
+                RedisUtils.getInstance().set(getGpsooTokenRedisKey(account, password),accessToken,postStr.getInt("expires_in")-3);
+            }
+            return accessToken;
+        }else {
+            logger.error("请求GPSOO获取token出错,错误信息"+postStr.get("msg"));
+        }
+        return null;
+    }
+
+
+    /**
+     * 跟踪
+     * @param account 账号
+     * @param password 密码
+     * @param imeis 设备号,可以逗号分隔
+     * @param mapType 地图类型 如果要显示在百度地图上,map_type=BAIDU此时返回的经纬度将经过baidu校准方式校准
+     * 如果要显示在google地图上,map_type=GOOGLE,此时返回的经纬度将经过google校准方式校准
+     * map_type如果不填,则返回原始经纬度
+     *
+     * @return
+     * <table>
+     * ret          uint    返回码 0:正确返回 其它: 失败。错误码 @see {@link com.beecode.inz.common.enumeration.GpsooErrorCodeEnum} <br/>
+     * msg          string	如果ret不为0,会有相应的错误信息提示<br/>
+     * imei	        string	设备imei<br/>
+     * device_info	uint	0:正常数据 1:设备未上线 2:设备已过期 3:设备离线<br/>
+     * gps_time	    number	设备定位时间,由设备在定位数据中上报。UTC秒数(如果设备过期,值为0)<br/>
+     * sys_time	    number	平台收到设备上报位置数据时的系统时间。 UTC秒数(如果设备过期,值为0)<br/>
+     * heart_time	number	设备与平台的最后通信时间。UTC秒数(如果设备过期,值为0)<br/>
+     * server_time	number	当前服务器时间。UTC秒数(如果设备过期,值为0)<br/>
+     * lng	        number	经度 (如果设备过期,值为0)<br/>
+     * lat	        number	纬度 (如果设备过期,值为0)<br/>
+     * course	    number	航向(正北方向为0度,顺时针方向增大。最大值360度) (如果设备过期,值为0)<br/>
+     * speed	    number	速度 (单位:km/h) <br/>
+     * status	    string	ACC等信息 (如果设备过期,值为空字符串) <br/>
+     * acc	        unit	-1,表示这个设备不支持ACC功能;否则为ACC的状态值(0=关闭,1=开启) <br/>
+     * acc_seconds	string	该设备切换为当前状态已经过的时长(单位:秒) <br/>
+     * </table>
+     * @throws  Exception
+     */
+
+    public static List<Map<String,Object>> tracking(String account, String password, String imeis, String mapType) throws Exception {
+        if(StringUtils.isEmpty(imeis)){
+            return null;
+        }
+        if(StringUtils.isEmpty(mapType)){
+            mapType="GOOGLE";
+        }
+        String commonParam = getCommonParam(account, password);
+
+        if(commonParam==null){
+            return null;
+        }
+        List<Map<String,Object>> imeisInfos = new ArrayList<>();
+        List<String> imeisInfoKey = new ArrayList<>();
+        String[] split = imeis.split(",");
+        for (String s : split) {
+            String s1 = RedisUtils.getInstance().get(getGpsooImeisTrackingRedisKey(account, password, s, mapType));
+            if(StringUtils.isNotEmpty(s1)){
+                imeisInfos.add(new JSONObject(s1).toMap());
+            }else {
+                imeisInfoKey.add(s);
+            }
+        }
+
+        String sendParam=commonParam +"&imeis="+String.join(",",imeisInfoKey)+"&map_type="+mapType;
+        String sendPost = HttpSendUtil.sendPost(TRACKING_URL, sendParam, StandardCharsets.UTF_8.name());
+        JSONObject postStr = new JSONObject(sendPost);
+        int ret = postStr.getInt("ret");
+        if (0==(ret)) {
+            JSONArray data = postStr.getJSONArray("data");
+            for (int i = 0; i < data.length(); i++) {
+                String imei = data.getJSONObject(i).getString("imei");
+                //每分钟限制了600次请求 8秒缓存,可能不大够..
+                JSONObject jsonObject = data.getJSONObject(i);
+                Map<String,Object> imeisInfo = jsonObject.toMap();
+                RedisUtils.getInstance().set(getGpsooImeisTrackingRedisKey(account, password, imei, mapType), jsonObject.toString(),8);
+                imeisInfos.add(imeisInfo);
+            }
+        }else {
+            logger.error("请求GPSOO监控获取tracking出错,错误信息"+postStr.get("msg")+",设备号列表"+imeis);
+        }
+        return imeisInfos;
+    }
+
+
+    /**
+     * 历史轨迹
+     * @param account 账号
+     * @param password 密码
+     * @param imei 设备号
+     * @param mapType 地图类型 如果要显示在百度地图上,map_type=BAIDU此时返回的经纬度将经过baidu校准方式校准
+     * 如果要显示在google地图上,map_type=GOOGLE,此时返回的经纬度将经过google校准方式校准
+     * map_type如果不填,则返回原始经纬度
+     * @param beginTime 开始时间(UTC) 秒数
+     * @param endTime 结束时间(UTC) 秒数。end_time不应大于当前时间。
+     * gps_time	number	gps定位时间 UTC秒数<br/>
+     * lng	number	经度<br/>
+     * lat	number	纬度<br/>
+     * course	number	航向(正北方向为0度,顺时针方向增大。最大值360度)<br/>
+     * speed	number	速度 (单位: km/h)<br/>
+     */
+    public static List<Object> history(String account, String password, String imei, String mapType,Long beginTime ,Long endTime,List<Object> datas) throws Exception {
+
+        if(StringUtils.isEmpty(imei)){
+            return null;
+        }
+        if(StringUtils.isEmpty(mapType)){
+            mapType="GOOGLE";
+        }
+        String commonParam = getCommonParam(account, password);
+
+        if(commonParam==null){
+            return null;
+        }
+        if(null==datas){
+            datas=new ArrayList<>();
+        }
+
+        String sendParam=commonParam +"&imei="+imei+"&map_type="+mapType+"&begin_time="+beginTime+"&end_time="+endTime;
+        String sendPost = HttpSendUtil.sendPost(HISTORY_URL, sendParam, StandardCharsets.UTF_8.name());
+        JSONObject postStr = new JSONObject(sendPost);
+        int ret = postStr.getInt("ret");
+        if (0==ret) {
+            JSONArray data = postStr.getJSONArray("data");
+            datas.addAll(data.toList());
+            if(data.length()>=1000){
+                JSONObject jsonObject = data.getJSONObject(999);
+                history(account, password, imei, mapType, jsonObject.getLong("gps_time"), endTime, datas);
+
+            }
+        }else {
+            logger.error("请求GPSOO历史获取出错,错误信息"+postStr.get("msg")+",设备号"+imei);
+        }
+        return datas;
+
+    }
+
+
+    private static String getCommonParam(String account,String password) throws Exception {
+        if(StringUtils.isEmpty(account)|| StringUtils.isEmpty(password)){
+            return null;
+        }
+        String tokenByAccount = getTokenByAccount(account, password);
+        String time = Long.toString(System.currentTimeMillis()/1000L);
+        return "account="+URLEncoder.encode(account, StandardCharsets.UTF_8.name())+"&access_token="+tokenByAccount+"&time="+time;
+    }
+
+
+
+
+
+
+}
diff --git a/backend/inz.common/src/main/java/com/beecode/inz/common/util/HttpSendUtil.java b/backend/inz.common/src/main/java/com/beecode/inz/common/util/HttpSendUtil.java
new file mode 100644
index 0000000..14c73a2
--- /dev/null
+++ b/backend/inz.common/src/main/java/com/beecode/inz/common/util/HttpSendUtil.java
@@ -0,0 +1,165 @@
+package com.beecode.inz.common.util;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+
+public class HttpSendUtil {
+
+    /**
+     * 向指定URL发送GET方法的请求
+     *
+     * @param url   发送请求的URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return URL 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url, String param) throws Exception {
+        StringBuilder result = new StringBuilder();
+        BufferedReader in = null;
+        try {
+            String urlNameString = url + "?" + param;
+            URL realUrl = new URL(urlNameString);
+            // 打开和URL之间的连接
+            URLConnection connection = realUrl.openConnection();
+            // 设置通用的请求属性
+            connection.setRequestProperty("accept", "*/*");
+            connection.setRequestProperty("connection", "Keep-Alive");
+            connection.setRequestProperty("user-agent",
+                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            // 建立实际的连接
+            connection.connect();
+            // 遍历所有的响应头字段
+            // 定义 BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+        } catch (Exception e) {
+            throw new Exception("发送GET请求出现异常");
+        }
+        // 使用finally块来关闭输入流
+        finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (Exception e2) {
+                e2.printStackTrace();
+            }
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * 向指定 URL 发送POST方法的请求
+     *
+     * @param url   发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式,outformate,out流中文的格式。
+     * @return 所代表远程资源的响应结果
+     * @author zouli
+     * @date 2019年7月22日 下午1:47:41
+     */
+    public static String sendPost(String url, String param, String outformate) throws Exception {
+        OutputStreamWriter out = null;
+        BufferedReader in = null;
+        String result;
+        try {
+            URLConnection conn = getUrlConnection(url);
+            // 获取URLConnection对象对应的输出流
+            out = new OutputStreamWriter(conn.getOutputStream(), outformate);
+            // 发送请求参数
+            out.write(param);
+            // flush输出流的缓冲
+            out.flush();
+            // 定义BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+            String lines;
+            StringBuilder sb = new StringBuilder();
+            while ((lines = in.readLine()) != null) {
+                lines = new String(lines.getBytes(), outformate);
+                sb.append(lines);
+            }
+            result = sb.toString();
+        } catch (Exception e) {
+            throw new Exception("发送 POST 请求出现异常!");
+        }
+        // 使用finally块来关闭输出流、输入流
+        finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return result;
+    }
+
+    private static URLConnection getUrlConnection(String url) throws IOException {
+        URL realUrl = new URL(url);
+        // 打开和URL之间的连接
+        URLConnection conn = realUrl.openConnection();
+        // 设置通用的请求属性
+        conn.setRequestProperty("accept", "*/*");
+        conn.setRequestProperty("connection", "Keep-Alive");
+        conn.setRequestProperty("user-agent",
+                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+        // 发送POST请求必须设置如下两行
+        conn.setDoOutput(true);
+        conn.setDoInput(true);
+        return conn;
+    }
+
+
+    /**
+     * 向指定 URL 发送POST方法的请求
+     *
+     * @param url   发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendPost(String url, String param) throws Exception {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try {
+            URLConnection conn = getUrlConnection(url);
+            // 获取URLConnection对象对应的输出流
+            out = new PrintWriter(conn.getOutputStream());
+            // 发送请求参数
+            out.print(param);
+            // flush输出流的缓冲
+            out.flush();
+            // 定义BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+        } catch (Exception e) {
+            throw new Exception("发送请求异常");
+        }
+        // 使用finally块来关闭输出流、输入流
+        finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return result.toString();
+    }
+
+}
diff --git a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/SandMiningAreaDao.java b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/SandMiningAreaDao.java
index 5966ea2..675bffa 100644
--- a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/SandMiningAreaDao.java
+++ b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/SandMiningAreaDao.java
@@ -25,5 +25,11 @@ public interface SandMiningAreaDao extends BaseDao {
 
     Object  groupByDischarging(List<UUID> regionalCompanyIds);
 
+    /**
+     *
+     * @param regionalCompanyIds
+     * @param isInclude 是否包含禁采区和流域
+     * @return
+     */
     List<KObject> listByRegionalCompanyIds(List<UUID> regionalCompanyIds, Boolean isInclude);
 }
diff --git a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/ShipInfoDao.java b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/ShipInfoDao.java
index 532be0c..bec6cd7 100644
--- a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/ShipInfoDao.java
+++ b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/dao/ShipInfoDao.java
@@ -22,4 +22,6 @@ public interface ShipInfoDao extends BaseDao {
     void modify(KObject kobject);
 
     List<KObject> getByCode(String code, UUID id);
+
+    List<KObject> getAllShipByRegionalCompanyIds(List<UUID> uuidList);
 }
diff --git a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/dao/ShipInfoDaoImpl.java b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/dao/ShipInfoDaoImpl.java
index 77a93b8..957bde5 100644
--- a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/dao/ShipInfoDaoImpl.java
+++ b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/dao/ShipInfoDaoImpl.java
@@ -11,6 +11,7 @@ import com.xyst.dinas.biz.constant.ShipInfoConstant;
 import com.xyst.dinas.biz.dao.DinasTypeDao;
 import com.xyst.dinas.biz.dao.ShipInfoDao;
 import com.xyst.dinas.biz.enumeration.OrganizationTypeEnum;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.criterion.DetachedCriteria;
 import org.hibernate.criterion.Order;
@@ -59,23 +60,27 @@ public class ShipInfoDaoImpl extends AbstractBaseDao implements ShipInfoDao, Shi
     @Override
     public Page<KObject> listPaging(Page<KObject> page, String shipName,
                                               String shipCodeNum) {
+        DetachedCriteria detachedCriteria = getDetachedCriteria(shipName, shipCodeNum);
+        dinasTypeDao.addRegionalCompanyFilter(detachedCriteria);
+        page.setTotal(template.findByCriteria(detachedCriteria).size());
+        int offset = page.getPageSize() * (page.getPageNo() - 1);
+        List<KObject> list = (List<KObject>) template.findByCriteria(detachedCriteria, offset, page.getPageSize());
+        page.setDatas(list);
+        return page;
+    }
+
+    private DetachedCriteria getDetachedCriteria(String shipName, String shipCodeNum) {
         KClass bean = Amino.getStaticMetadataContext().getBean(ENTITY, KClass.class);
         DetachedCriteria detachedCriteria = DetachedCriteria.forEntityName(bean.getName());
         detachedCriteria.add(Restrictions.eq("del", false));
-        dinasTypeDao.addRegionalCompanyFilter(detachedCriteria);
         if(StringUtils.isNotBlank(shipName)){
-            detachedCriteria.add(Restrictions.like("shipName", "%"+shipName+"%"));
-
+            detachedCriteria.add(Restrictions.like("shipName", "%"+ shipName +"%"));
         }
         if(StringUtils.isNotBlank(shipCodeNum)){
-            detachedCriteria.add(Restrictions.like("shipCodeNum", "%"+shipCodeNum+"%"));
+            detachedCriteria.add(Restrictions.like("shipCodeNum", "%"+ shipCodeNum +"%"));
         }
         detachedCriteria.addOrder(Order.desc("sortOrder"));
-        page.setTotal(template.findByCriteria(detachedCriteria).size());
-        int offset = page.getPageSize() * (page.getPageNo() - 1);
-        List<KObject> list = (List<KObject>) template.findByCriteria(detachedCriteria, offset, page.getPageSize());
-        page.setDatas(list);
-        return page;
+        return detachedCriteria;
     }
 
 
@@ -116,6 +121,15 @@ public class ShipInfoDaoImpl extends AbstractBaseDao implements ShipInfoDao, Shi
         return (List<KObject>) template.findByCriteria(detachedCriteria);
     }
 
+    @Override
+    public List<KObject> getAllShipByRegionalCompanyIds(List<UUID> uuidList) {
+        DetachedCriteria detachedCriteria = getDetachedCriteria(null, null);
+        if(CollectionUtils.isNotEmpty(uuidList)){
+            detachedCriteria.add(Restrictions.in("regionalCompany",uuidList));
+        }
+        return (List<KObject>) template.findByCriteria(detachedCriteria);
+    }
+
 
     @Override
     public UUID create(KObject kObject) {
diff --git a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/SandMiningAreaServiceImpl.java b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/SandMiningAreaServiceImpl.java
index 0e8fdab..635eab1 100644
--- a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/SandMiningAreaServiceImpl.java
+++ b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/SandMiningAreaServiceImpl.java
@@ -131,6 +131,7 @@ public class SandMiningAreaServiceImpl implements SandMiningAreaService {
                     area.put("id",kObject.getUuid("id"));
                     area.put("sandMiningAreaName",kObject.getString("sandMiningAreaName"));
                     area.put("sandMiningQuantity",kObject.getDouble("sandMiningQuantity"));
+                    area.put("stationCoordinate",kObject.getString("stationCoordinate"));
                     Object sandMiningAreas = stringObjectHashMap.get("sandMiningAreas");
                     if(null!=sandMiningAreas){
                         sandMiningAreas1= (ArrayList<HashMap<String, Object>>) sandMiningAreas;
@@ -147,6 +148,10 @@ public class SandMiningAreaServiceImpl implements SandMiningAreaService {
         return regionalCompanyList;
     }
 
+    @Override
+    public List<KObject> getAllSandMiningAreaByRegionalCompanyIds(List<UUID> uuidList) {
+        return  sandMiningAreaDao.listByRegionalCompanyIds (uuidList,true);
+    }
 
 
 }
diff --git a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/ShipInfoServiceImpl.java b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/ShipInfoServiceImpl.java
index c89a355..361e06e 100644
--- a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/ShipInfoServiceImpl.java
+++ b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/internal/service/ShipInfoServiceImpl.java
@@ -2,14 +2,17 @@ package com.xyst.dinas.biz.internal.service;
 
 import com.beecode.bap.attachment.common.Page;
 import com.beecode.bcp.type.KObject;
+import com.beecode.inz.common.BaseConstants;
+import com.beecode.inz.common.util.GpsOOUtil;
 import com.xyst.dinas.biz.dao.ShipInfoDao;
 import com.xyst.dinas.biz.service.ShipInfoService;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.List;
-import java.util.UUID;
+import java.util.*;
 
 @Transactional(rollbackFor = Exception.class)
 public class ShipInfoServiceImpl implements ShipInfoService {
@@ -61,5 +64,49 @@ public class ShipInfoServiceImpl implements ShipInfoService {
         if(CollectionUtils.isEmpty(kObjects)){
             return null;
         }
-        return kObjects.get(0);    }
+        return kObjects.get(0);
+    }
+
+    @Override
+    public List<KObject> getAllShipByRegionalCompanyIds(List<UUID> uuidList) {
+        return shipInfoDao.getAllShipByRegionalCompanyIds(uuidList);
+    }
+
+    @Override
+    public List<Map<String, Object>> getShipsTracking(List<KObject> allShipByRegionalCompanyIds) throws Exception {
+        List<Map<String, Object>> list = new ArrayList<>();
+        Map<String, Object> stringObjectHashMap;
+        for (KObject allShipByRegionalCompanyId : allShipByRegionalCompanyIds) {
+            String account = allShipByRegionalCompanyId.getString("account");
+            String accountPassword = allShipByRegionalCompanyId.getString("accountPassword");
+            String imei = allShipByRegionalCompanyId.getString("deviceNumber");
+
+            stringObjectHashMap = new HashMap<>();
+            stringObjectHashMap.put("shipInfo",allShipByRegionalCompanyId);
+            stringObjectHashMap.put("shipInfoId",allShipByRegionalCompanyId.getUuid(BaseConstants.ID));
+
+            if(StringUtils.isEmpty(account)||StringUtils.isEmpty(accountPassword)||StringUtils.isEmpty(imei)){
+                stringObjectHashMap.put("trackingInfo",new ArrayList<>());
+                continue;
+            }
+            List<Map<String,Object>> tracking = GpsOOUtil.tracking(account, accountPassword, imei, null);
+            stringObjectHashMap.put("trackingInfo",tracking);
+
+            list.add(stringObjectHashMap);
+        }
+        return list;
+    }
+
+    @Override
+    public List<Object> getShipHistoryById(UUID uuid, Long startTime, Long endTime) throws Exception {
+            KObject load = shipInfoDao.load(uuid);
+            String account = load.getString("account");
+            String accountPassword = load.getString("accountPassword");
+            String imei = load.getString("deviceNumber");
+
+            if(StringUtils.isEmpty(account)||StringUtils.isEmpty(accountPassword)||StringUtils.isEmpty(imei)){
+                return null;
+            }
+        return GpsOOUtil.history(account, accountPassword, imei, null, startTime, endTime, null);
+    }
 }
diff --git a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/SandMiningAreaService.java b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/SandMiningAreaService.java
index 9e41f44..81b46e2 100644
--- a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/SandMiningAreaService.java
+++ b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/SandMiningAreaService.java
@@ -26,4 +26,7 @@ public interface SandMiningAreaService {
     Object groupByDischarging(List<UUID> regionalCompanyIds);
 
     List<HashMap<String, Object>> listByRegionalCompanyIds(List<UUID> regionalCompanyIds, Boolean isInclude);
+
+    List<KObject> getAllSandMiningAreaByRegionalCompanyIds(List<UUID> uuidList);
+
 }
diff --git a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/ShipInfoService.java b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/ShipInfoService.java
index aa6a5dd..dd3a68f 100644
--- a/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/ShipInfoService.java
+++ b/backend/xyst.dinas.biz/src/main/java/com/xyst/dinas/biz/service/ShipInfoService.java
@@ -2,7 +2,10 @@ package com.xyst.dinas.biz.service;
 
 import com.beecode.bap.attachment.common.Page;
 import com.beecode.bcp.type.KObject;
+import org.json.JSONObject;
 
+import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 public interface ShipInfoService {
@@ -20,4 +23,10 @@ public interface ShipInfoService {
     void deleteById(UUID id);
 
     KObject getByCode(String code, UUID id);
+
+    List<KObject> getAllShipByRegionalCompanyIds(List<UUID> uuidList);
+
+    List<Map<String, Object>> getShipsTracking(List<KObject> allShipByRegionalCompanyIds) throws Exception;
+
+    List<Object> getShipHistoryById(UUID uuid, Long startTime, Long endTime) throws Exception;
 }
diff --git a/backend/xyst.dinas.camera/build.gradle b/backend/xyst.dinas.camera/build.gradle
index 15acda9..5292c29 100644
--- a/backend/xyst.dinas.camera/build.gradle
+++ b/backend/xyst.dinas.camera/build.gradle
@@ -20,8 +20,8 @@ dependencies {
     compile project(":inz.basis")
     compile project(":inz.authentication")
     compile project(":xyst.dinas.biz")
-    compile project(":xyst.dinas.production")
     compile project(":xyst.dinas.project")
+    compile project(":xyst.dinas.transport")
 
 
     testCompile lib.amino_boot_web
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/config/CameraPlayConfiguration.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/config/CameraPlayConfiguration.java
index e92eaa2..ff70d44 100644
--- a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/config/CameraPlayConfiguration.java
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/config/CameraPlayConfiguration.java
@@ -5,6 +5,7 @@ import com.xyst.dinas.camera.internal.dao.CameraPlayDaoImpl;
 import com.xyst.dinas.camera.internal.service.CameraPlayServiceImpl;
 import com.xyst.dinas.camera.service.CameraPlayService;
 import com.xyst.dinas.camera.web.CameraPlayController;
+import com.xyst.dinas.camera.web.WatershedCameraPlayController;
 import org.springframework.context.annotation.Bean;
 
 public class CameraPlayConfiguration {
@@ -22,6 +23,10 @@ public class CameraPlayConfiguration {
     public CameraPlayController cameraPlayController(){
         return new CameraPlayController();
     }
+    @Bean
+    public WatershedCameraPlayController watershedCameraPlayController(){
+        return new WatershedCameraPlayController();
+    }
 
 
 }
\ No newline at end of file
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/dao/CameraInfoDao.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/dao/CameraInfoDao.java
index de1ecaf..d373473 100644
--- a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/dao/CameraInfoDao.java
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/dao/CameraInfoDao.java
@@ -20,4 +20,6 @@ public interface CameraInfoDao extends BaseDao {
     List<KObject> getByName(String name, UUID id);
 
     void modify(KObject kobject, KObject currentLoginRegionalCompany);
+
+    List<KObject> getWatershedCameraTreeByRegionalCompanyIds(List<UUID> uuidList);
 }
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/RegionalCompanyWatershedCameraTree.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/RegionalCompanyWatershedCameraTree.java
new file mode 100644
index 0000000..8930839
--- /dev/null
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/RegionalCompanyWatershedCameraTree.java
@@ -0,0 +1,35 @@
+package com.xyst.dinas.camera.entity;
+
+import java.util.List;
+import java.util.UUID;
+
+public class RegionalCompanyWatershedCameraTree {
+    private String regionalCompanyName;
+    private UUID regionalCompanyId;
+    private List<WatershedCameraTree> watershedCameraTreeList;
+
+    public UUID getRegionalCompanyId() {
+        return regionalCompanyId;
+    }
+
+    public void setRegionalCompanyId(UUID regionalCompanyId) {
+        this.regionalCompanyId = regionalCompanyId;
+    }
+
+    public String getRegionalCompanyName() {
+        return regionalCompanyName;
+    }
+
+    public void setRegionalCompanyName(String regionalCompanyName) {
+        this.regionalCompanyName = regionalCompanyName;
+    }
+
+    public List<WatershedCameraTree> getWatershedCameraTreeList() {
+        return watershedCameraTreeList;
+    }
+
+    public void setWatershedCameraTreeList(List<WatershedCameraTree> watershedCameraTreeList) {
+        this.watershedCameraTreeList = watershedCameraTreeList;
+    }
+}
+
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/WatershedCameraTree.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/WatershedCameraTree.java
new file mode 100644
index 0000000..a976c4d
--- /dev/null
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/entity/WatershedCameraTree.java
@@ -0,0 +1,36 @@
+package com.xyst.dinas.camera.entity;
+
+import com.beecode.bcp.type.KObject;
+
+import java.util.List;
+import java.util.UUID;
+
+public class WatershedCameraTree {
+    private UUID watershedId;
+    private String watershedName;
+    private List<KObject> cameraList;
+
+    public UUID getWatershedId() {
+        return watershedId;
+    }
+
+    public void setWatershedId(UUID watershedId) {
+        this.watershedId = watershedId;
+    }
+
+    public String getWatershedName() {
+        return watershedName;
+    }
+
+    public void setWatershedName(String watershedName) {
+        this.watershedName = watershedName;
+    }
+
+    public List<KObject> getCameraList() {
+        return cameraList;
+    }
+
+    public void setCameraList(List<KObject> cameraList) {
+        this.cameraList = cameraList;
+    }
+}
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/dao/CameraInfoDaoImpl.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/dao/CameraInfoDaoImpl.java
index 831a8e2..3b19847 100644
--- a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/dao/CameraInfoDaoImpl.java
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/dao/CameraInfoDaoImpl.java
@@ -7,9 +7,10 @@ import com.beecode.bcp.type.KClass;
 import com.beecode.bcp.type.KObject;
 import com.beecode.inz.basis.internal.dao.AbstractBaseDao;
 import com.beecode.inz.common.BaseConstants;
+import com.xyst.dinas.biz.dao.DinasTypeDao;
 import com.xyst.dinas.camera.constant.CameraInfoConstant;
 import com.xyst.dinas.camera.dao.CameraInfoDao;
-import com.xyst.dinas.biz.enumeration.OrganizationTypeEnum;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.criterion.DetachedCriteria;
 import org.hibernate.criterion.Order;
@@ -25,6 +26,8 @@ public class CameraInfoDaoImpl extends AbstractBaseDao implements CameraInfoDao,
 
     @Autowired
     private HibernateTemplate template;
+    @Autowired
+    private DinasTypeDao dinasTypeDao;
 
     /**
      * 抽象方法,需要实现类提供HibernateTemplate
@@ -54,28 +57,32 @@ public class CameraInfoDaoImpl extends AbstractBaseDao implements CameraInfoDao,
 
     @Override
     public Page<KObject> listCameraInfoPaging(Page<KObject> page, UUID stationId, UUID watershedId, String cameraName, KObject currentLoginRegionalCompany) {
+        DetachedCriteria detachedCriteria = commonDetachedCriteria(stationId, watershedId, cameraName);
+        page.setTotal(template.findByCriteria(detachedCriteria).size());
+        dinasTypeDao.addRegionalCompanyFilter(detachedCriteria);
+        int offset = page.getPageSize() * (page.getPageNo() - 1);
+        List<KObject> list = (List<KObject>) template.findByCriteria(detachedCriteria, offset, page.getPageSize());
+        page.setDatas(list);
+        return page;
+    }
+
+    private DetachedCriteria commonDetachedCriteria(UUID stationId, UUID watershedId, String cameraName) {
         KClass bean = Amino.getStaticMetadataContext().getBean(ENTITY, KClass.class);
 
         DetachedCriteria detachedCriteria = DetachedCriteria.forEntityName(bean.getName());
         detachedCriteria.add(Restrictions.eq("del", false));
-        if(currentLoginRegionalCompany!=null&&currentLoginRegionalCompany.getString("type").equals(OrganizationTypeEnum.REGIONAL_COMPANY.name())) {
-            detachedCriteria.add(Restrictions.eq("regionalCompany.id", currentLoginRegionalCompany.getUuid("id")));
-        }
+
         detachedCriteria.addOrder(Order.desc("sortOrder"));
-        if(null!=stationId){
+        if(null!= stationId){
             detachedCriteria.add(Restrictions.eq("regionalStation.id", stationId));
         }
-        if(null!=watershedId){
+        if(null!= watershedId){
             detachedCriteria.add(Restrictions.eq("watershed.id", watershedId));
         }
         if(StringUtils.isNotBlank(cameraName)){
-            detachedCriteria.add(Restrictions.like("cameraName", "%"+cameraName+"%"));
+            detachedCriteria.add(Restrictions.like("cameraName", "%"+ cameraName +"%"));
         }
-        page.setTotal(template.findByCriteria(detachedCriteria).size());
-        int offset = page.getPageSize() * (page.getPageNo() - 1);
-        List<KObject> list = (List<KObject>) template.findByCriteria(detachedCriteria, offset, page.getPageSize());
-        page.setDatas(list);
-        return page;
+        return detachedCriteria;
     }
 
 
@@ -114,6 +121,16 @@ public class CameraInfoDaoImpl extends AbstractBaseDao implements CameraInfoDao,
         template.merge(kobject);
     }
 
+    @Override
+    public List<KObject> getWatershedCameraTreeByRegionalCompanyIds(List<UUID> uuidList) {
+        DetachedCriteria detachedCriteria = commonDetachedCriteria(null, null, null);
+        if(CollectionUtils.isNotEmpty(uuidList)){
+            detachedCriteria.add(Restrictions.in("regionalCompany",uuidList));
+        }
+        detachedCriteria.add(Restrictions.eq("cameraObject",1));
+        return (List<KObject>)template.findByCriteria(detachedCriteria);
+    }
+
 
     @Override
     public UUID create(KObject object, KObject regionalCompany) {
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/service/CameraInfoServiceImpl.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/service/CameraInfoServiceImpl.java
index 53ef7fa..5df32c7 100644
--- a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/service/CameraInfoServiceImpl.java
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/internal/service/CameraInfoServiceImpl.java
@@ -3,18 +3,20 @@ package com.xyst.dinas.camera.internal.service;
 import com.beecode.bap.attachment.common.Page;
 import com.beecode.bap.staff.BapContext;
 import com.beecode.bcp.type.KObject;
+import com.beecode.inz.common.BaseConstants;
 import com.xyst.dinas.camera.dao.CameraInfoDao;
+import com.xyst.dinas.camera.entity.RegionalCompanyWatershedCameraTree;
+import com.xyst.dinas.camera.entity.WatershedCameraTree;
 import com.xyst.dinas.camera.service.CameraInfoService;
 import com.xyst.dinas.biz.service.DinasOrganizationService;
+import com.xyst.dinas.camera.service.CameraPlayService;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
 
 @Transactional(rollbackFor = Exception.class)
 public class CameraInfoServiceImpl implements CameraInfoService {
@@ -24,6 +26,8 @@ public class CameraInfoServiceImpl implements CameraInfoService {
     @Autowired
     private DinasOrganizationService dinasOrganizationService;
     @Autowired
+    private CameraPlayService cameraPlayService;
+    @Autowired
     private BapContext bapContext;
 
     @Override
@@ -80,4 +84,64 @@ public class CameraInfoServiceImpl implements CameraInfoService {
         }
         return  null;
     }
+
+    @Override
+    public List<RegionalCompanyWatershedCameraTree> getWatershedCameraTreeByRegionalCompanyIds(List<UUID> uuidList) {
+        List<KObject> watershedCameraTreeByRegionalCompanyIds = cameraInfoDao.getWatershedCameraTreeByRegionalCompanyIds(uuidList);
+        RegionalCompanyWatershedCameraTree regionalCompanyWatershedCameraTree;
+        List<RegionalCompanyWatershedCameraTree> regionalCompanyWatershedCameraTreeList = new ArrayList<>();
+        HashMap<String, RegionalCompanyWatershedCameraTree> regionalCompanyWatershedCameraTreeHashMap = new HashMap<>(12);
+
+        WatershedCameraTree watershedCameraTree;
+        HashMap<String, WatershedCameraTree> watershedCameraTreeDetail = new HashMap<>();
+
+        List<KObject> cameraList;
+        for (KObject watershedCameraTreeByRegionalCompanyId : watershedCameraTreeByRegionalCompanyIds) {
+            watershedCameraTreeByRegionalCompanyId = watershedCameraTreeByRegionalCompanyId.clone();
+            KObject regionalCompany = watershedCameraTreeByRegionalCompanyId.get("regionalCompany");
+            String regionalCompanyId = regionalCompany.getUuid(BaseConstants.ID).toString();
+            String regionalCompanyName = regionalCompany.getString("name");
+            KObject watershed = watershedCameraTreeByRegionalCompanyId.get("watershed");
+            String watershedId = watershed.getUuid(BaseConstants.ID).toString();
+            String watershedName = watershed.getString("sandMiningAreaName");
+            if(!regionalCompanyWatershedCameraTreeHashMap.containsKey(regionalCompanyId)){
+                regionalCompanyWatershedCameraTree = new RegionalCompanyWatershedCameraTree();
+                regionalCompanyWatershedCameraTree.setRegionalCompanyId(UUID.fromString(regionalCompanyId));
+                regionalCompanyWatershedCameraTree.setRegionalCompanyName(regionalCompanyName);
+                regionalCompanyWatershedCameraTree.setWatershedCameraTreeList(new ArrayList<>());
+                regionalCompanyWatershedCameraTreeHashMap.put(regionalCompanyId, regionalCompanyWatershedCameraTree);
+                regionalCompanyWatershedCameraTreeList.add(regionalCompanyWatershedCameraTree);
+            }else {
+                regionalCompanyWatershedCameraTree = regionalCompanyWatershedCameraTreeHashMap.get(regionalCompanyId);
+            }
+            watershedCameraTree = getWatershedCameraTree(regionalCompanyWatershedCameraTree, watershedCameraTreeDetail, watershedName, watershedId);
+            cameraList = watershedCameraTree.getCameraList();
+            String picUrl = cameraPlayService.capturePic(watershedCameraTreeByRegionalCompanyId.getUuid(BaseConstants.ID),watershedCameraTreeByRegionalCompanyId.getString("deviceSerial"),watershedCameraTreeByRegionalCompanyId.getString("channelNo"));
+            watershedCameraTreeByRegionalCompanyId.set("videoUrl",picUrl);
+            cameraList.add(watershedCameraTreeByRegionalCompanyId);
+        }
+
+        return regionalCompanyWatershedCameraTreeList;
+
+
+    }
+
+    private WatershedCameraTree getWatershedCameraTree(RegionalCompanyWatershedCameraTree regionalCompanyWatershedCameraTree, HashMap<String, WatershedCameraTree> watershedCameraTreeDetail, String watershedName, String watershedId) {
+        List<WatershedCameraTree> watershedCameraTreeList;
+        WatershedCameraTree watershedCameraTree;
+        if (!watershedCameraTreeDetail.containsKey(watershedId + regionalCompanyWatershedCameraTree.getRegionalCompanyId())) {
+            watershedCameraTree = new WatershedCameraTree();
+            watershedCameraTree.setWatershedId(UUID.fromString(watershedId));
+            watershedCameraTree.setWatershedName(watershedName);
+            watershedCameraTreeDetail.put(watershedId + regionalCompanyWatershedCameraTree.getRegionalCompanyId(), watershedCameraTree);
+            watershedCameraTreeList = regionalCompanyWatershedCameraTree.getWatershedCameraTreeList();
+            watershedCameraTree.setCameraList(new ArrayList<>());
+            watershedCameraTreeList.add(watershedCameraTree);
+        } else {
+            watershedCameraTree = watershedCameraTreeDetail.get(watershedId + regionalCompanyWatershedCameraTree.getRegionalCompanyId());
+        }
+        return watershedCameraTree;
+
+    }
+
 }
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/service/CameraInfoService.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/service/CameraInfoService.java
index 051f5ee..d3c5d9c 100644
--- a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/service/CameraInfoService.java
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/service/CameraInfoService.java
@@ -2,7 +2,9 @@ package com.xyst.dinas.camera.service;
 
 import com.beecode.bap.attachment.common.Page;
 import com.beecode.bcp.type.KObject;
+import com.xyst.dinas.camera.entity.RegionalCompanyWatershedCameraTree;
 
+import java.util.List;
 import java.util.UUID;
 
 public interface CameraInfoService {
@@ -19,4 +21,6 @@ public interface CameraInfoService {
 
     void deleteById(UUID id);
     public KObject getCurrentLoginRegionalCompany();
+
+    List<RegionalCompanyWatershedCameraTree> getWatershedCameraTreeByRegionalCompanyIds(List<UUID> uuidList);
 }
diff --git a/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/web/WatershedCameraPlayController.java b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/web/WatershedCameraPlayController.java
new file mode 100644
index 0000000..207043d
--- /dev/null
+++ b/backend/xyst.dinas.camera/src/main/java/com/xyst/dinas/camera/web/WatershedCameraPlayController.java
@@ -0,0 +1,76 @@
+package com.xyst.dinas.camera.web;
+
+
+import com.beecode.bcp.type.KObject;
+import com.beecode.inz.basis.team.pojo.ResponseObj;
+import com.xyst.dinas.biz.service.SandMiningAreaService;
+import com.xyst.dinas.biz.service.ShipInfoService;
+import com.xyst.dinas.camera.entity.RegionalCompanyWatershedCameraTree;
+import com.xyst.dinas.camera.service.CameraInfoService;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * @author scol
+ */
+@RequestMapping("/cameraPlay/watershed")
+@RestController
+public class WatershedCameraPlayController {
+
+    @Autowired
+    private CameraInfoService cameraInfoService;
+
+    @Autowired
+    private SandMiningAreaService sandMiningAreaService;
+
+    @Autowired
+    private ShipInfoService shipInfoService;
+
+    /**
+     * 获取摄像头树列表
+     * @param uuidList
+     * @return
+     */
+    @GetMapping(value = "/getWatershedCameraTreeByRegionalCompanyIds")
+    public ResponseObj<List<RegionalCompanyWatershedCameraTree>> getWatershedCameraTreeByRegionalCompanyIds(@RequestParam(name = "uuidList",required = false) List<UUID> uuidList) {
+        List<RegionalCompanyWatershedCameraTree> watershedCameraTreeByRegionalCompanyIds = cameraInfoService.getWatershedCameraTreeByRegionalCompanyIds(uuidList);
+        return ResponseObj.response(200, "查询成功", watershedCameraTreeByRegionalCompanyIds);
+    }
+
+    /**
+     * 获取所有采区
+     */
+    @GetMapping(value = "/getAllSandMiningAreaByRegionalCompanyIds")
+    public ResponseObj<List<KObject>> getAllSandMiningAreaByRegionalCompanyIds(@RequestParam(name = "uuidList",required = false) List<UUID> uuidList) {
+        return ResponseObj.response(200, "查询成功", sandMiningAreaService.getAllSandMiningAreaByRegionalCompanyIds(uuidList));
+    }
+
+
+    /**
+     * 获取所有船只
+     */
+
+    @GetMapping(value = "/getAllShipByRegionalCompanyIds")
+    public ResponseObj<List<Map<String,Object>>> getAllShipByRegionalCompanyIds(@RequestParam(name = "uuidList",required = false) List<UUID> uuidList) throws Exception {
+        List<KObject> allShipByRegionalCompanyIds = shipInfoService.getAllShipByRegionalCompanyIds(uuidList);
+        return ResponseObj.response(200, "查询成功",shipInfoService.getShipsTracking(allShipByRegionalCompanyIds) );
+    }
+
+
+    /**
+     * 获取船只历史轨迹
+     * @return
+     */
+
+    @GetMapping(value = "/getShipHistoryById")
+    public ResponseObj<List<Object>> getShipHistoryById(@RequestParam(name = "id") UUID uuid,@RequestParam(name = "startTime")Long startTime,@RequestParam(name = "endTime")Long endTime) throws Exception {
+        List<Object> allShipByRegionalCompanyIds = shipInfoService.getShipHistoryById(uuid,startTime,endTime);
+        return ResponseObj.response(200, "查询成功",allShipByRegionalCompanyIds );
+    }
+
+
+
+}
--
libgit2 0.26.0