Commit 9571eb3a15046bf12dae06f58d567b9a8a307e66

Authored by Lawrence
1 parent b0088b8b

增加移动位置显示功能

README.md
... ... @@ -42,6 +42,14 @@ https://gitee.com/18010473990/wvp-GB28181.git
42 42 12. 支持播放h265, g.711格式的流
43 43 13. 支持固定流地址和自动点播,同时支持未点播时直接播放流地址,代码自动发起点播. ( [查看WIKI](https://github.com/648540858/wvp-GB28181-pro/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E5%9B%BA%E5%AE%9A%E6%92%AD%E6%94%BE%E5%9C%B0%E5%9D%80%E4%B8%8E%E8%87%AA%E5%8A%A8%E7%82%B9%E6%92%AD))
44 44 14. 报警信息处理,支持向前端推送报警信息
  45 +15. 支持订阅与通知方法
  46 + [X] 移动位置订阅
  47 + [X] 移动位置通知处理
  48 + [ ] 报警事件订阅
  49 + [X] 报警事件通知处理
  50 + [ ] 设备目录订阅
  51 + [X] 设备奴鲁通知处理
  52 +16. 移动位置查询和显示,可通过配置文件设置移动位置历史是否存储
45 53  
46 54 # 待实现:
47 55 上级级联
... ...
web_src/index.html
... ... @@ -7,6 +7,7 @@
7 7 </head>
8 8 <body>
9 9 <script type="text/javascript" src="./js/EasyWasmPlayer.js"></script>
  10 + <script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=rk73w8dv1rkE4UdZsataG68VarhYQzrx&s=1"></script>
10 11 <div id="app"></div>
11 12 <!-- built files will be auto injected -->
12 13 </body>
... ...
web_src/package-lock.json
... ... @@ -1269,6 +1269,34 @@
1269 1269 "integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=",
1270 1270 "dev": true
1271 1271 },
  1272 + "bmaplib.curveline": {
  1273 + "version": "1.0.0",
  1274 + "resolved": "https://registry.npmjs.org/bmaplib.curveline/-/bmaplib.curveline-1.0.0.tgz",
  1275 + "integrity": "sha512-9wcFMVhiYxNPqpvsLDAADn3qDhNzXp2mA6VyHSHg2XOAgSooC7ZiujdFhy0sp+0QYjTfJ/MjmLuNoUg2HHxH4Q=="
  1276 + },
  1277 + "bmaplib.heatmap": {
  1278 + "version": "1.0.4",
  1279 + "resolved": "https://registry.npmjs.org/bmaplib.heatmap/-/bmaplib.heatmap-1.0.4.tgz",
  1280 + "integrity": "sha512-rmhqUARBpUSJ9jXzUI2j7dIOqnc38bqubkx/8a349U2qtw/ulLUwyzRD535OrA8G7w5cz4aPKm6/rNvUAarg/Q=="
  1281 + },
  1282 + "bmaplib.lushu": {
  1283 + "version": "1.0.7",
  1284 + "resolved": "https://registry.npmjs.org/bmaplib.lushu/-/bmaplib.lushu-1.0.7.tgz",
  1285 + "integrity": "sha512-LVvgpESPii6xGxyjnQjq8u+ic4NjvhdCPV/RiSS/PGTUdZKeTDS7prSpleJLZH3ES0+oc0gYn8bw0LtPYUSz2w=="
  1286 + },
  1287 + "bmaplib.markerclusterer": {
  1288 + "version": "1.0.13",
  1289 + "resolved": "https://registry.npmjs.org/bmaplib.markerclusterer/-/bmaplib.markerclusterer-1.0.13.tgz",
  1290 + "integrity": "sha512-VrLyWSiuDEVNi0yUfwOhFQ6z1oEEHS4w36GNu3iASu6p52QIx9uAXMUkuSCHReNR0bj2Cp9SA1dSx5RpojXajQ==",
  1291 + "requires": {
  1292 + "bmaplib.texticonoverlay": "^1.0.2"
  1293 + }
  1294 + },
  1295 + "bmaplib.texticonoverlay": {
  1296 + "version": "1.0.2",
  1297 + "resolved": "https://registry.npmjs.org/bmaplib.texticonoverlay/-/bmaplib.texticonoverlay-1.0.2.tgz",
  1298 + "integrity": "sha512-4ZTWr4ZP3B6qEWput5Tut16CfZgII38YwM3bpyb4gFTQyORlKYryFp9WHWrwZZaHlOyYDAXG9SX0hka43jTADg=="
  1299 + },
1272 1300 "bn.js": {
1273 1301 "version": "5.1.3",
1274 1302 "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-5.1.3.tgz",
... ... @@ -5266,6 +5294,14 @@
5266 5294 "invert-kv": "^1.0.0"
5267 5295 }
5268 5296 },
  5297 + "linkify-it": {
  5298 + "version": "2.2.0",
  5299 + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
  5300 + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
  5301 + "requires": {
  5302 + "uc.micro": "^1.0.1"
  5303 + }
  5304 + },
5269 5305 "load-json-file": {
5270 5306 "version": "2.0.0",
5271 5307 "resolved": "https://registry.npm.taobao.org/load-json-file/download/load-json-file-2.0.0.tgz",
... ... @@ -5443,6 +5479,25 @@
5443 5479 "object-visit": "^1.0.0"
5444 5480 }
5445 5481 },
  5482 + "markdown-it": {
  5483 + "version": "8.4.2",
  5484 + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
  5485 + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==",
  5486 + "requires": {
  5487 + "argparse": "^1.0.7",
  5488 + "entities": "~1.1.1",
  5489 + "linkify-it": "^2.0.0",
  5490 + "mdurl": "^1.0.1",
  5491 + "uc.micro": "^1.0.5"
  5492 + },
  5493 + "dependencies": {
  5494 + "entities": {
  5495 + "version": "1.1.2",
  5496 + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
  5497 + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
  5498 + }
  5499 + }
  5500 + },
5446 5501 "math-expression-evaluator": {
5447 5502 "version": "1.2.22",
5448 5503 "resolved": "https://registry.npm.taobao.org/math-expression-evaluator/download/math-expression-evaluator-1.2.22.tgz",
... ... @@ -5466,6 +5521,11 @@
5466 5521 "integrity": "sha1-aZs8OKxvHXKAkaZGULZdOIUC/Vs=",
5467 5522 "dev": true
5468 5523 },
  5524 + "mdurl": {
  5525 + "version": "1.0.1",
  5526 + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
  5527 + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
  5528 + },
5469 5529 "media-typer": {
5470 5530 "version": "0.3.0",
5471 5531 "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz",
... ... @@ -10074,8 +10134,7 @@
10074 10134 "sprintf-js": {
10075 10135 "version": "1.0.3",
10076 10136 "resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz",
10077   - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
10078   - "dev": true
  10137 + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
10079 10138 },
10080 10139 "ssri": {
10081 10140 "version": "5.3.0",
... ... @@ -10489,6 +10548,11 @@
10489 10548 "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
10490 10549 "dev": true
10491 10550 },
  10551 + "uc.micro": {
  10552 + "version": "1.0.6",
  10553 + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
  10554 + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
  10555 + },
10492 10556 "uglify-js": {
10493 10557 "version": "3.4.10",
10494 10558 "resolved": "https://registry.npm.taobao.org/uglify-js/download/uglify-js-3.4.10.tgz?cache=0&sync_timestamp=1601823880483&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuglify-js%2Fdownload%2Fuglify-js-3.4.10.tgz",
... ... @@ -10841,6 +10905,18 @@
10841 10905 "resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.12.tgz?cache=0&sync_timestamp=1600441238751&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue%2Fdownload%2Fvue-2.6.12.tgz",
10842 10906 "integrity": "sha1-9evU+mvShpQD4pqJau1JBEVskSM="
10843 10907 },
  10908 + "vue-baidu-map": {
  10909 + "version": "0.21.22",
  10910 + "resolved": "https://registry.npmjs.org/vue-baidu-map/-/vue-baidu-map-0.21.22.tgz",
  10911 + "integrity": "sha512-WQMPCih4UTh0AZCKKH/OVOYnyAWjfRNeK6BIeoLmscyY5aF8zzlJhz/NOHLb3mdztIpB0Z6aohn4Jd9mfCSjQw==",
  10912 + "requires": {
  10913 + "bmaplib.curveline": "^1.0.0",
  10914 + "bmaplib.heatmap": "^1.0.4",
  10915 + "bmaplib.lushu": "^1.0.7",
  10916 + "bmaplib.markerclusterer": "^1.0.13",
  10917 + "markdown-it": "^8.4.0"
  10918 + }
  10919 + },
10844 10920 "vue-clipboard2": {
10845 10921 "version": "0.3.1",
10846 10922 "resolved": "https://registry.npm.taobao.org/vue-clipboard2/download/vue-clipboard2-0.3.1.tgz",
... ...
web_src/package.json
... ... @@ -19,6 +19,7 @@
19 19 "moment": "^2.29.1",
20 20 "postcss-pxtorem": "^5.1.1",
21 21 "vue": "^2.6.11",
  22 + "vue-baidu-map": "^0.21.22",
22 23 "vue-clipboard2": "^0.3.1",
23 24 "vue-cookies": "^1.7.4",
24 25 "vue-router": "^3.1.6"
... ...
web_src/src/components/GeoConvertTools.js 0 → 100644
  1 +/**
  2 + * 经纬度转换
  3 + */
  4 +export default {
  5 + PI: 3.1415926535897932384626,
  6 + //PI: 3.14159265358979324,
  7 + x_pi: (3.1415926535897932384626 * 3000.0) / 180.0,
  8 + delta: function (lat, lng) {
  9 + // Krasovsky 1940
  10 + //
  11 + // a = 6378245.0, 1/f = 298.3
  12 + // b = a * (1 - f)
  13 + // ee = (a^2 - b^2) / a^2;
  14 + var a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
  15 + var ee = 0.00669342162296594323; // ee: 椭球的偏心率。
  16 + var dLat = this.transformLat(lng - 105.0, lat - 35.0);
  17 + var dLng = this.transformLng(lng - 105.0, lat - 35.0);
  18 + var radLat = (lat / 180.0) * this.PI;
  19 + var magic = Math.sin(radLat);
  20 + magic = 1 - ee * magic * magic;
  21 + var sqrtMagic = Math.sqrt(magic);
  22 + dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * this.PI);
  23 + dLng = (dLng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * this.PI);
  24 + return {
  25 + lat: dLat,
  26 + lng: dLng
  27 + };
  28 + },
  29 + /**
  30 + * WGS-84 to GCJ-02 GPS坐标转中国坐标
  31 + * @param {number} wgsLat GPS纬度
  32 + * @param {number} wgsLng GPS经度
  33 + * @return {object} 返回中国坐标经纬度对象
  34 + */
  35 + GPSToChina: function (wgsLat, wgsLng) {
  36 + if (this.outOfChina(wgsLat, wgsLng)) return {
  37 + lat: wgsLat,
  38 + lng: wgsLng
  39 + };
  40 + var d = this.delta(wgsLat, wgsLng);
  41 + return {
  42 + lat: Number(wgsLat) + Number(d.lat),
  43 + lng: Number(wgsLng) + Number(d.lng)
  44 + };
  45 + },
  46 + /**
  47 + * GCJ-02 to WGS-84 中国标准坐标转GPS坐标
  48 + * @param {number} gcjLat 中国标准坐标纬度
  49 + * @param {number} gcjLng 中国标准坐标经度
  50 + * @return {object} 返回GPS经纬度对象
  51 + */
  52 + chinaToGPS: function (gcjLat, gcjLng) {
  53 + if (this.outOfChina(gcjLat, gcjLng)) return {
  54 + lat: gcjLat,
  55 + lng: gcjLng
  56 + };
  57 + var d = this.delta(gcjLat, gcjLng);
  58 + return {
  59 + lat: Number(gcjLat) - Number(d.lat),
  60 + lng: Number(gcjLng) - Number(d.lng)
  61 + };
  62 + },
  63 + /**
  64 + * GCJ-02 to WGS-84 exactly 中国标准坐标转GPS坐标(精确)
  65 + * @param {number} gcjLat 中国标准坐标纬度
  66 + * @param {number} gcjLng 中国标准坐标经度
  67 + * @return {object} 返回GPS经纬度对象(精确)
  68 + */
  69 + chinaToGPSExact: function (gcjLat, gcjLng) {
  70 + var initDelta = 0.01;
  71 + var threshold = 0.000000001;
  72 + var dLat = initDelta,
  73 + dLng = initDelta;
  74 + var mLat = gcjLat - dLat,
  75 + mLng = gcjLng - dLng;
  76 + var pLat = gcjLat + dLat,
  77 + pLng = gcjLng + dLng;
  78 + var wgsLat,
  79 + wgsLng,
  80 + i = 0;
  81 + while (1) {
  82 + wgsLat = (mLat + pLat) / 2;
  83 + wgsLng = (mLng + pLng) / 2;
  84 + var tmp = this.gcj_encrypt(wgsLat, wgsLng);
  85 + dLat = tmp.lat - gcjLat;
  86 + dLng = tmp.lng - gcjLng;
  87 + if (Math.abs(dLat) < threshold && Math.abs(dLng) < threshold) break;
  88 +
  89 + if (dLat > 0) pLat = wgsLat;
  90 + else mLat = wgsLat;
  91 + if (dLng > 0) pLng = wgsLng;
  92 + else mLng = wgsLng;
  93 +
  94 + if (++i > 10000) break;
  95 + }
  96 + //console.log(i);
  97 + return {
  98 + lat: wgsLat,
  99 + lng: wgsLng
  100 + };
  101 + },
  102 + /**
  103 + * GCJ-02 to BD-09 中国标准坐标转百度坐标(精确)
  104 + * @param {number} gcjLat 中国标准坐标纬度
  105 + * @param {number} gcjLng 中国标准坐标经度
  106 + * @return {object} 返回百度经纬度对象
  107 + */
  108 + chinaToBaidu: function (gcjLat, gcjLng) {
  109 + var x = gcjLng,
  110 + y = gcjLat;
  111 + var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * this.x_pi);
  112 + var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * this.x_pi);
  113 + var bdLng = z * Math.cos(theta) + 0.0065;
  114 + var bdLat = z * Math.sin(theta) + 0.006;
  115 + return {
  116 + lat: bdLat,
  117 + lng: bdLng
  118 + };
  119 + },
  120 + /**
  121 + * BD-09 to GCJ-02 百度坐标转中国标准坐标
  122 + * @param {number} bdLat 百度坐标纬度
  123 + * @param {number} bdLng 百度坐标经度
  124 + * @return {object} 返回中国标准经纬度对象
  125 + */
  126 + baiduToChina: function (bdLat, bdLng) {
  127 + var x = bdLng - 0.0065,
  128 + y = bdLat - 0.006;
  129 + var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_pi);
  130 + var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_pi);
  131 + var gcjLng = z * Math.cos(theta);
  132 + var gcjLat = z * Math.sin(theta);
  133 + return {
  134 + lat: gcjLat,
  135 + lng: gcjLng
  136 + };
  137 + },
  138 + /**
  139 + * BD-09 to GCJ-02 百度坐标转gps坐标
  140 + * @param {number} bdLat 百度坐标纬度
  141 + * @param {number} bdLng 百度坐标经度
  142 + * @return {object} 返回gps经纬度对象
  143 + */
  144 + baiduToGPS: function (bdLat, bdLng) {
  145 + let china = this.baiduToChina(bdLat, bdLng);
  146 + return this.chinaToGPS(china.lat, china.lng);
  147 + },
  148 + /**
  149 + * WGS-84 to to BD-09 GPS坐标转Baidu坐标
  150 + * @param {number} gpsLat GPS纬度
  151 + * @param {number} gpsLng GPS经度
  152 + * @return {object} 返回百度经纬度对象
  153 + */
  154 + GPSToBaidu: function (gpsLat, gpsLng) {
  155 + var china = this.GPSToChina(gpsLat, gpsLng);
  156 + return this.chinaToBaidu(china.lat, china.lng);
  157 + },
  158 + /**
  159 + * WGS-84 to Web mercator GPS坐标转墨卡托坐标
  160 + * @param {number} wgsLat GPS纬度
  161 + * @param {number} wgsLng GPS经度
  162 + * @return {object} 返回墨卡托经纬度对象
  163 + */
  164 + GPSToMercator: function (wgsLat, wgsLng) {
  165 + var x = (wgsLng * 20037508.34) / 180;
  166 + var y = Math.log(Math.tan(((90 + wgsLat) * this.PI) / 360)) / (this.PI / 180);
  167 + y = (y * 20037508.34) / 180;
  168 + return {
  169 + lat: y,
  170 + lng: x
  171 + };
  172 + /*
  173 + if ((Math.abs(wgsLng) > 180 || Math.abs(wgsLat) > 90))
  174 + return null;
  175 + var x = 6378137.0 * wgsLng * 0.017453292519943295;
  176 + var a = wgsLat * 0.017453292519943295;
  177 + var y = 3189068.5 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
  178 + return {'lat' : y, 'lng' : x};
  179 + //*/
  180 + },
  181 + /**
  182 + * Web mercator to WGS-84 墨卡托坐标转GPS坐标
  183 + * @param {number} mercatorLat 墨卡托纬度
  184 + * @param {number} mercatorLng 墨卡托经度
  185 + * @return {object} 返回GPS经纬度对象
  186 + */
  187 + mercatorToGPS: function (mercatorLat, mercatorLng) {
  188 + var x = (mercatorLng / 20037508.34) * 180;
  189 + var y = (mercatorLat / 20037508.34) * 180;
  190 + y = (180 / this.PI) * (2 * Math.atan(Math.exp((y * this.PI) / 180)) - this.PI / 2);
  191 + return {
  192 + lat: y,
  193 + lng: x
  194 + };
  195 + /*
  196 + if (Math.abs(mercatorLng) < 180 && Math.abs(mercatorLat) < 90)
  197 + return null;
  198 + if ((Math.abs(mercatorLng) > 20037508.3427892) || (Math.abs(mercatorLat) > 20037508.3427892))
  199 + return null;
  200 + var a = mercatorLng / 6378137.0 * 57.295779513082323;
  201 + var x = a - (Math.floor(((a + 180.0) / 360.0)) * 360.0);
  202 + var y = (1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * mercatorLat) / 6378137.0)))) * 57.295779513082323;
  203 + return {'lat' : y, 'lng' : x};
  204 + //*/
  205 + },
  206 + /**
  207 + * 两点之间的距离
  208 + * @param {number} latA 起点纬度
  209 + * @param {number} lngA 起点经度
  210 + * @param {number} latB 终点纬度
  211 + * @param {number} lngB 终点经度
  212 + * @return {number} 返回距离(米)
  213 + */
  214 + distance: function (latA, lngA, latB, lngB) {
  215 + var earthR = 6371000;
  216 + var x = Math.cos((latA * this.PI) / 180) * Math.cos((latB * this.PI) / 180) * Math.cos(((lngA - lngB) * this.PI) / 180);
  217 + var y = Math.sin((latA * this.PI) / 180) * Math.sin((latB * this.PI) / 180);
  218 + var s = x + y;
  219 + if (s > 1) s = 1;
  220 + if (s < -1) s = -1;
  221 + var alpha = Math.acos(s);
  222 + var distance = alpha * earthR;
  223 + return distance;
  224 + },
  225 + /**
  226 + * 是否在中国之外
  227 + * @param {number} lat 纬度
  228 + * @param {number} lng 经度
  229 + * @return {boolean]} 返回结果真或假
  230 + */
  231 + outOfChina: function (lat, lng) {
  232 + if (lat < 72.004 || lat > 137.8347) return true;
  233 + if (lng < 0.8293 || lng > 55.8271) return true;
  234 + return false;
  235 + },
  236 + transformLat: function (x, y) {
  237 + var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
  238 + ret += ((20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0) / 3.0;
  239 + ret += ((20.0 * Math.sin(y * this.PI) + 40.0 * Math.sin((y / 3.0) * this.PI)) * 2.0) / 3.0;
  240 + ret += ((160.0 * Math.sin((y / 12.0) * this.PI) + 320 * Math.sin((y * this.PI) / 30.0)) * 2.0) / 3.0;
  241 + return ret;
  242 + },
  243 + transformLng: function (x, y) {
  244 + var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
  245 + ret += ((20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0) / 3.0;
  246 + ret += ((20.0 * Math.sin(x * this.PI) + 40.0 * Math.sin((x / 3.0) * this.PI)) * 2.0) / 3.0;
  247 + ret += ((150.0 * Math.sin((x / 12.0) * this.PI) + 300.0 * Math.sin((x / 30.0) * this.PI)) * 2.0) / 3.0;
  248 + return ret;
  249 + }
  250 +};
... ...
web_src/src/components/devicePosition.vue 0 → 100644
  1 +<template>
  2 + <div id="devicePosition" style="height: 100%">
  3 + <el-container style="height: 100%">
  4 + <el-header>
  5 + <uiHeader></uiHeader>
  6 + </el-header>
  7 + <el-main>
  8 + <div style="background-color: #ffffff; position: relative; padding: 1rem 0.5rem 0.5rem 0.5rem; text-align: center;">
  9 + <span style="font-size: 1rem; font-weight: 500">设备定位 ({{ parentChannelId == 0 ? deviceId : parentChannelId }})</span>
  10 + </div>
  11 + <div style="background-color: #ffffff; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left; font-size: 14px;">
  12 + <el-button icon="el-icon-arrow-left" size="mini" style="margin-right: 1rem" type="primary" @click="showDevice">返回</el-button>
  13 + <!-- <span class="demonstration">从</span> -->
  14 + <el-date-picker v-model="searchFrom" type="datetime" placeholder="选择开始日期时间" default-time="00:00:00" size="mini" style="width: 11rem;" align="right" :picker-options="pickerOptions"></el-date-picker>
  15 + <el-date-picker v-model="searchTo" type="datetime" placeholder="选择结束日期时间" default-time="00:00:00" size="mini" style="width: 11rem;" align="right" :picker-options="pickerOptions"></el-date-picker>
  16 + <el-button-group>
  17 + <el-button icon="el-icon-search" size="mini" type="primary" @click="showHistoryPath">历史轨迹</el-button>
  18 + <el-button icon="el-icon-search" size="mini" style="margin-right: 1rem" type="primary" @click="showLatestPosition">最新位置</el-button>
  19 + </el-button-group>
  20 + <el-tag style="width: 5rem; text-align: center" size="medium">过期时间</el-tag>
  21 + <el-input-number size="mini" v-model="expired" :min="300" :controls="false" style="width: 4rem;"></el-input-number>
  22 + <el-tag style="width: 5rem; text-align: center" size="medium">上报周期</el-tag>
  23 + <el-input-number size="mini" v-model="interval" :min="1" :controls="false" style="width: 4rem;"></el-input-number>
  24 + <el-button-group>
  25 + <el-button icon="el-icon-search" size="mini" type="primary" @click="subscribeMobilePosition">位置订阅</el-button>
  26 + <el-button icon="el-icon-search" size="mini" type="primary" @click="unSubscribeMobilePosition">取消订阅</el-button>
  27 + </el-button-group>
  28 + <el-checkbox size="mini" style="margin-right: 1rem; float: right" v-model="autoList" @change="autoListChange" >自动刷新</el-checkbox>
  29 + </div>
  30 + <div class="mapContainer" style="background-color: #ffffff; position: relative; padding: 1rem 0.5rem 0.5rem 0.5rem; text-align: center; height: calc(100% - 10rem);">
  31 + <div class="baidumap" id="allmap"></div>
  32 + </div>
  33 + </el-main>
  34 + </el-container>
  35 + </div>
  36 +</template>
  37 +
  38 +<script>
  39 +import uiHeader from "./UiHeader.vue";
  40 +import moment from "moment";
  41 +import geoTools from "./GeoConvertTools.js";
  42 +export default {
  43 + name: "devicePosition",
  44 + components: {
  45 + uiHeader,
  46 + },
  47 + data() {
  48 + return {
  49 + pickerOptions: {
  50 + shortcuts: [{
  51 + text: '今天',
  52 + onClick(picker) {
  53 + picker.$emit('pick', new Date());
  54 + }
  55 + }, {
  56 + text: '昨天',
  57 + onClick(picker) {
  58 + const date = new Date();
  59 + date.setTime(date.getTime() - 3600 * 1000 * 24);
  60 + picker.$emit('pick', date);
  61 + }
  62 + }, {
  63 + text: '一周前',
  64 + onClick(picker) {
  65 + const date = new Date();
  66 + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
  67 + picker.$emit('pick', date);
  68 + }
  69 + }]
  70 + },
  71 + deviceId: this.$route.params.deviceId,
  72 + showHistoryPosition: false, //显示历史轨迹
  73 + startTime: null,
  74 + endTime: null,
  75 + searchFrom: null,
  76 + searchTo: null,
  77 + expired: 600,
  78 + interval: 5,
  79 + mobilePositionList: [],
  80 + mapPointList: [],
  81 + parentChannelId: this.$route.params.parentChannelId,
  82 + updateLooper: 0, //数据刷新轮训标志
  83 + total: 0,
  84 + beforeUrl: "/videoList",
  85 + isLoging: false,
  86 + autoList: false,
  87 + };
  88 + },
  89 + mounted() {
  90 + this.initData();
  91 + this.initBaiduMap();
  92 + if (this.autoList) {
  93 + this.updateLooper = setInterval(this.initData, 5000);
  94 + }
  95 + },
  96 + destroyed() {
  97 + // this.$destroy("videojs");
  98 + clearTimeout(this.updateLooper);
  99 + },
  100 + methods: {
  101 + initData: function () {
  102 + // if (this.parentChannelId == "" || this.parentChannelId == 0) {
  103 + // this.getDeviceChannelList();
  104 + // } else {
  105 + // this.showSubchannels();
  106 + // }
  107 + },
  108 + initParam: function () {
  109 + // this.deviceId = this.$route.params.deviceId;
  110 + // this.parentChannelId = this.$route.params.parentChannelId;
  111 + // this.currentPage = parseInt(this.$route.params.page);
  112 + // this.count = parseInt(this.$route.params.count);
  113 + // if (this.parentChannelId == "" || this.parentChannelId == 0) {
  114 + // this.beforeUrl = "/videoList";
  115 + // }
  116 + },
  117 + initBaiduMap() {
  118 + this.map = new BMap.Map("allmap"); // 创建地图实例
  119 + let points = [];
  120 + let point = new BMap.Point(116.231398, 39.567445); // 创建点坐标
  121 + this.map.centerAndZoom(point, 5); // 初始化地图,设置中心点坐标和地图级别
  122 + this.map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
  123 + this.map.addControl(new BMap.NavigationControl());
  124 + this.map.addControl(new BMap.ScaleControl());
  125 + this.map.addControl(new BMap.OverviewMapControl());
  126 + this.map.addControl(new BMap.MapTypeControl());
  127 + //map.setMapStyle({ style: 'midnight' }) //地图风格
  128 + },
  129 + currentChange: function (val) {
  130 + // var url = `/${this.$router.currentRoute.name}/${this.deviceId}/${this.parentChannelId}/${this.count}/${val}`;
  131 + // console.log(url);
  132 + // this.$router.push(url).then(() => {
  133 + // this.initParam();
  134 + // this.initData();
  135 + // });
  136 + },
  137 + handleSizeChange: function (val) {
  138 + // var url = `/${this.$router.currentRoute.name}/${this.$router.params.deviceId}/${this.$router.params.parentChannelId}/${val}/1`;
  139 + // this.$router.push(url).then(() => {
  140 + // this.initParam();
  141 + // this.initData();
  142 + // });
  143 + },
  144 + showDevice: function () {
  145 + this.$router.push(this.beforeUrl).then(() => {
  146 + this.initParam();
  147 + this.initData();
  148 + });
  149 + },
  150 + autoListChange: function () {
  151 + if (this.autoList) {
  152 + this.updateLooper = setInterval(this.initData, 1500);
  153 + } else {
  154 + window.clearInterval(this.updateLooper);
  155 + }
  156 + },
  157 + showHistoryPath: function () {
  158 + this.map.clearOverlays();
  159 + this.mapPointList = [];
  160 + this.mobilePositionList = [];
  161 + if (!!this.searchFrom) {
  162 + this.startTime = this.toGBString(this.searchFrom);
  163 + console.log(this.startTime);
  164 + } else{
  165 + this.startTime = null;
  166 + }
  167 + if (!!this.searchTo) {
  168 + this.endTime = this.toGBString(this.searchTo);
  169 + console.log(this.endTime);
  170 + } else {
  171 + this.endTime = null;
  172 + }
  173 + let self = this;
  174 + this.$axios.get(`/api/positions/${this.deviceId}/history`, {
  175 + params: {
  176 + start: self.startTime,
  177 + end: self.endTime,
  178 + },
  179 + })
  180 + .then(function (res) {
  181 + self.total = res.data.length;
  182 + self.mobilePositionList = res.data;
  183 + console.log(self.mobilePositionList);
  184 + // 防止出现表格错位
  185 + self.$nextTick(() => {
  186 + self.showMarkPoints(self);
  187 + });
  188 + })
  189 + .catch(function (error) {
  190 + console.log(error);
  191 + });
  192 + },
  193 + showLatestPosition: function() {
  194 + this.map.clearOverlays();
  195 + this.mapPointList = [];
  196 + this.mobilePositionList = [];
  197 + let self = this;
  198 + this.$axios.get(`/api/positions/${this.deviceId}/latest`)
  199 + .then(function (res) {
  200 + console.log(res.data);
  201 + self.total = res.data.length;
  202 + self.mobilePositionList.push(res.data);
  203 + console.log(self.mobilePositionList);
  204 + // 防止出现表格错位
  205 + self.$nextTick(() => {
  206 + self.showMarkPoints(self);
  207 + });
  208 + })
  209 + .catch(function (error) {
  210 + console.log(error);
  211 + });
  212 + },
  213 + subscribeMobilePosition: function() {
  214 + let self = this;
  215 + this.$axios.get(`/api/positions/${this.deviceId}/subscribe`, {
  216 + params: {
  217 + expires: self.expired,
  218 + interval: self.interval,
  219 + },
  220 + })
  221 + .then(function (res) {
  222 + console.log(res.data);
  223 + })
  224 + .catch(function (error) {
  225 + console.log(error);
  226 + });
  227 + },
  228 + unSubscribeMobilePosition: function() {
  229 + let self = this;
  230 + this.$axios.get(`/api/positions/${this.deviceId}/subscribe`, {
  231 + params: {
  232 + expires: 0,
  233 + interval: self.interval,
  234 + },
  235 + })
  236 + .then(function (res) {
  237 + console.log(res.data);
  238 + })
  239 + .catch(function (error) {
  240 + console.log(error);
  241 + });
  242 + },
  243 + toGBString: function (dateTime) {
  244 + return (
  245 + dateTime.getFullYear() +
  246 + "-" + this.twoDigits(dateTime.getMonth() + 1) +
  247 + "-" + this.twoDigits(dateTime.getDate()) +
  248 + "T" + this.twoDigits(dateTime.getHours()) +
  249 + ":" + this.twoDigits(dateTime.getMinutes()) +
  250 + ":" + this.twoDigits(dateTime.getSeconds())
  251 + );
  252 + },
  253 + twoDigits: function (num) {
  254 + if (num < 10) {
  255 + return "0" + num;
  256 + } else {
  257 + return "" + num;
  258 + }
  259 + },
  260 + showMarkPoints: function(self) {
  261 + let that = self;
  262 + let npointJ = null;
  263 + let npointW = null;
  264 + let point = null;
  265 + for (let i = 0; i < self.mobilePositionList.length; i++) {
  266 + if (self.mobilePositionList[i].geodeticSystem == "BD-09") {
  267 + npointJ = self.mobilePositionList[i].cnLng;
  268 + npointW = self.mobilePositionList[i].cnLat;
  269 + point = new BMap.Point(npointJ, npointW);
  270 + } else {
  271 + npointJ = self.mobilePositionList[i].longitude;
  272 + npointW = self.mobilePositionList[i].latitude;
  273 + let bd2 = geoTools.GPSToBaidu(npointJ, npointW);
  274 + point = new BMap.Point(bd2.lat, bd2.lng);
  275 + }
  276 + self.mapPointList.push(point);
  277 + let marker = new BMap.Marker(point); // 创建标注
  278 + self.map.addOverlay(marker); // 将标注添加到地图中
  279 + //提示信息 可以解析 HTML标签以及CSS
  280 + let infoWindow = new BMap.InfoWindow(`<p style='text-align:left;font-weight:800'>设备: ${self.mobilePositionList[i].deviceId}</p>
  281 + <p style='text-align:left;font-weight:0'>时间: ${self.mobilePositionList[i].time}</p>`);
  282 + // 鼠标移上标注点要发生的事
  283 + marker.addEventListener("mouseover", function () {
  284 + this.openInfoWindow(infoWindow);
  285 + });
  286 + // 鼠标移开标注点要发生的事
  287 + marker.addEventListener("mouseout", function () {
  288 + this.closeInfoWindow(infoWindow);
  289 + });
  290 + // 鼠标点击标注点要发生的事情
  291 + marker.addEventListener("click", function () {
  292 + alert("点击");
  293 + });
  294 + }
  295 + let view = that.map.getViewport(eval(self.mapPointList));
  296 + that.map.centerAndZoom(view.center, view.zoom);
  297 + },
  298 + },
  299 +};
  300 +</script>
  301 +
  302 +<style>
  303 +.videoList {
  304 + display: flex;
  305 + flex-wrap: wrap;
  306 + align-content: flex-start;
  307 +}
  308 +
  309 +.video-item {
  310 + position: relative;
  311 + width: 15rem;
  312 + height: 10rem;
  313 + margin-right: 1rem;
  314 + background-color: #000000;
  315 +}
  316 +
  317 +.video-item-img {
  318 + position: absolute;
  319 + top: 0;
  320 + bottom: 0;
  321 + left: 0;
  322 + right: 0;
  323 + margin: auto;
  324 + width: 100%;
  325 + height: 100%;
  326 +}
  327 +
  328 +.video-item-img:after {
  329 + content: "";
  330 + display: inline-block;
  331 + position: absolute;
  332 + z-index: 2;
  333 + top: 0;
  334 + bottom: 0;
  335 + left: 0;
  336 + right: 0;
  337 + margin: auto;
  338 + width: 3rem;
  339 + height: 3rem;
  340 + background-image: url("../assets/loading.png");
  341 + background-size: cover;
  342 + background-color: #000000;
  343 +}
  344 +
  345 +.video-item-title {
  346 + position: absolute;
  347 + bottom: 0;
  348 + color: #000000;
  349 + background-color: #ffffff;
  350 + line-height: 1.5rem;
  351 + padding: 0.3rem;
  352 + width: 14.4rem;
  353 +}
  354 +
  355 +.baidumap {
  356 + width: 100%;
  357 + height: 100%;
  358 + border: none;
  359 + position: absolute;
  360 + left: 0;
  361 + top: 0;
  362 + right: 0;
  363 + bottom: 0;
  364 + margin: auto;
  365 +}
  366 +
  367 +/* 去除百度地图版权那行字 和 百度logo */
  368 +.baidumap > .BMap_cpyCtrl {
  369 + display: none !important;
  370 +}
  371 +.baidumap > .anchorBL {
  372 + display: none !important;
  373 +}
  374 +</style>
... ...
web_src/src/components/videoList.vue
... ... @@ -11,7 +11,7 @@
11 11 <el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button>
12 12 </div>
13 13 </div>
14   - <devicePlayer ref="devicePlayer"></devicePlayer>
  14 + <!-- <devicePlayer ref="devicePlayer"></devicePlayer> -->
15 15 <!--设备列表-->
16 16 <el-table :data="deviceList" border style="width: 100%" :height="winHeight">
17 17 <el-table-column prop="name" label="名称" width="180" align="center">
... ... @@ -40,7 +40,7 @@
40 40 </el-table-column>
41 41 <el-table-column prop="channelCount" label="通道数" align="center">
42 42 </el-table-column>
43   - <el-table-column label="状态" width="180" align="center">
  43 + <el-table-column label="状态" width="80" align="center">
44 44 <template slot-scope="scope">
45 45 <div slot="reference" class="name-wrapper">
46 46 <el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag>
... ... @@ -49,10 +49,11 @@
49 49 </template>
50 50 </el-table-column>
51 51  
52   - <el-table-column label="操作" width="240" align="center" fixed="right">
  52 + <el-table-column label="操作" width="360" align="center" fixed="right">
53 53 <template slot-scope="scope">
54 54 <el-button size="mini" :ref="scope.row.deviceId + 'refbtn' " icon="el-icon-refresh" @click="refDevice(scope.row)">刷新通道</el-button>
55 55 <el-button size="mini" icon="el-icon-s-open" v-bind:disabled="scope.row.online==0" type="primary" @click="showChannelList(scope.row)">查看通道</el-button>
  56 + <el-button size="mini" icon="el-icon-s-open" v-bind:disabled="scope.row.online==0" type="primary" @click="showDevicePosition(scope.row)">移动位置</el-button>
56 57 </template>
57 58 </el-table-column>
58 59 </el-table>
... ... @@ -73,7 +74,7 @@
73 74 </template>
74 75  
75 76 <script>
76   - import uiHeader from './UiHeader.vue'
  77 + import uiHeader from './UiHeader.vue'
77 78 export default {
78 79 name: 'app',
79 80 components: {
... ... @@ -155,7 +156,10 @@
155 156 console.log(JSON.stringify(row))
156 157 this.$router.push(`/channelList/${row.deviceId}/0/15/1`);
157 158 },
158   -
  159 + showDevicePosition: function(row) {
  160 + console.log(JSON.stringify(row))
  161 + this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`);
  162 + },
159 163  
160 164 //gb28181平台对接
161 165 //刷新设备信息
... ... @@ -191,18 +195,18 @@
191 195 },
192 196 //通知设备上传媒体流
193 197 sendDevicePush: function(itemData) {
194   - let deviceId = this.currentDevice.deviceId;
195   - let channelId = itemData.channelId;
196   - console.log("通知设备推流1:" + deviceId + " : " + channelId);
197   - let that = this;
198   - this.$axios({
199   - method: 'get',
200   - url: '/api/play/' + deviceId + '/' + channelId
201   - }).then(function(res) {
202   - let ssrc = res.data.ssrc;
203   - that.$refs.devicePlayer.play(ssrc,deviceId,channelId);
204   - }).catch(function(e) {
205   - });
  198 + // let deviceId = this.currentDevice.deviceId;
  199 + // let channelId = itemData.channelId;
  200 + // console.log("通知设备推流1:" + deviceId + " : " + channelId);
  201 + // let that = this;
  202 + // this.$axios({
  203 + // method: 'get',
  204 + // url: '/api/play/' + deviceId + '/' + channelId
  205 + // }).then(function(res) {
  206 + // let ssrc = res.data.ssrc;
  207 + // that.$refs.devicePlayer.play(ssrc,deviceId,channelId);
  208 + // }).catch(function(e) {
  209 + // });
206 210 },
207 211 transportChange: function (row) {
208 212 console.log(row);
... ...
web_src/src/main.js
... ... @@ -12,21 +12,21 @@ import VueClipboard from &#39;vue-clipboard2&#39;;
12 12 import { Notification } from 'element-ui';
13 13 import Fingerprint2 from 'fingerprintjs2';
14 14  
15   -// 生成唯一ID
  15 +// 鐢熸垚鍞竴ID
16 16 Fingerprint2.get(function(components) {
17 17 const values = components.map(function(component,index) {
18   - if (index === 0) { //把微信浏览器里UA的wifi或4G等网络替换成空,不然切换网络会ID不一样
  18 + if (index === 0) { //鎶婂井淇℃祻瑙堝櫒閲孶A鐨剋ifi鎴G绛夌綉缁滄浛鎹㈡垚绌,涓嶇劧鍒囨崲缃戠粶浼欼D涓嶄竴鏍
19 19 return component.value.replace(/\bNetType\/\w+\b/, '');
20 20 }
21 21 return component.value;
22 22 })
23   - //console.log(values) //使用的浏览器信息npm
24   - // 生成最终id
  23 + //console.log(values) //浣跨敤鐨勬祻瑙堝櫒淇℃伅npm
  24 + // 鐢熸垚鏈缁坕d
25 25 let port = window.location.port;
26 26 console.log(port);
27 27 const fingerPrint = Fingerprint2.x64hash128(values.join(port), 31)
28 28 Vue.prototype.$browserId = fingerPrint;
29   - console.log("唯一标识码:" + fingerPrint);
  29 + console.log("鍞竴鏍囪瘑鐮侊細" + fingerPrint);
30 30 });
31 31  
32 32 Vue.use(VueClipboard);
... ...
web_src/src/router/index.js
... ... @@ -4,6 +4,7 @@ import VueRouter from &#39;vue-router&#39;
4 4 import control from '../components/control.vue'
5 5 import videoList from '../components/videoList.vue'
6 6 import channelList from '../components/channelList.vue'
  7 +import devicePosition from '../components/devicePosition.vue'
7 8 import login from '../components/Login.vue'
8 9  
9 10 const originalPush = VueRouter.prototype.push
... ... @@ -35,5 +36,10 @@ export default new VueRouter({
35 36 name: 'channelList',
36 37 component: channelList,
37 38 },
  39 + {
  40 + path: '/devicePosition/:deviceId/:parentChannelId/:count/:page',
  41 + name: 'devicePosition',
  42 + component: devicePosition,
  43 + },
38 44 ]
39 45 })
... ...