var vm; var app; var node; var device; var connection; var connectionId; var isApp = false; var flvPlayer; var timer; var decodedFrames; var isiOS = new MobileDetect(window.navigator.userAgent).os()==='iOS'; //func $.ajaxSetup({ cache: false, timeout: 5000 }); $('body').on('click', 'img.shot', function () { $(this).toggleClass('zoom'); }); function ajax(url) { console.log(url); app.dialog.progress(); $.get(url, function (response) { var result = response; if (result.code === 0) { if (result.type === 0) { if (result.format === 1) { console.log('format/1/base64 jpeg image'); $('#callback .page-content').html(''); } else { console.log('format/0/json object'); $('#callback .page-content').html(result.data); } app.popup.open('#callback'); } } }).fail(function (result) { console.log('error'); console.log(result); }).always(function () { app.dialog.close(); });; } function connect() { if (connection && connection.connection.connectionState === 1) { console.log('has connected'); } else { console.log('start connect to server:' + Date()); connection.start().then(function () { console.log('signalR>start'); }).catch(function (err) { console.error(err.toString()); setTimeout(connect, 10 * 1000); }); } } function onMessage() { connection.on('Connected', function (id) { connectionId = id; }); connection.on('ApiResult', function (result) { result = JSON.parse(result); if (result.code === 0) { if (result.type === 0) { if (result.format === 1) { console.log('format/1/base64 jpeg image'); $('#callback .page-content').html(''); } else { console.log('format/0/json object'); $('#callback .page-content').html(result.data); } app.popup.open('#callback'); } } }); connection.on("UpdateNode", (message) => { var newNode = JSON.parse(message); var oldNode = _.chain(vm.Nodes).filter(o => o.Number === newNode.Number).first().value(); oldNode.Name = newNode.Name; if (node && node.Node.Number === newNode.Number) { node.Node.Name = newNode.Name; } console.log('update:' + newNode.Name); }); connection.on("UpdateDevice", (message) => { var newDevice = JSON.parse(message); while (vm.Messages.length >= 20) { vm.Messages.pop(); } vm.Messages.push(newDevice); if (node && node.Node.Id == newDevice.NodeId) { var update = false; for (var i = 0; i < node.Node.Devices.length; i++) { if (node.Node.Devices[i].Number == newDevice.Number) { update = true; break; } } if (update) { node.Node.Devices.splice(i, 1, newDevice); } else { node.Node.Devices.push(newDevice); } } if (device && device.Device.Number == newDevice.Number) { device.Device.Name = newDevice.Name; device.Device.DisplayName = newDevice.DisplayName; device.Device.Data = newDevice.Data; updateChart(); } }); connection.on("DeleteDevice", (message) => { var newDevice = JSON.parse(message); if (node && node.Node.Id === newDevice.NodeId) { for (var i = 0; i < node.Node.Devices.length; i++) { if (node.Node.Devices[i].Number == newDevice.Number) { node.Node.Devices.splice(i, 1); break; } } console.log('delete:' + newDevice.Number); } }); connection.on("UpdateSence", function (message) { var sence = JSON.parse(message); if (node && node.Node.Id === sence.NodeId) { var update = false; for (var i = 0; i < node.Node.Sences.length; i++) { if (node.Node.Sences[i].Id == sence.Id) { update = true; break; } } if (update) { node.Node.Sences.splice(i, 1, sence); } else { node.Node.Sences.push(sence); } console.log('update:' + sence.DisplayName); } }); connection.on("DeleteSence", function (message) { var sence = JSON.parse(message); if (node && node.Node.Id === sence.NodeId) { for (var i = 0; i < node.Node.Sences.length; i++) { if (node.Node.Sences[i].Id == sence.Id) { node.Node.Sences.splice(i, 1); break; } } console.log('delete:' + sence.Name); } }); connection.onclose(function () { setTimeout(connect, 10 * 1000); }); } function playFlv(url) { var id = 'flvPlayer'; var videoElement = document.getElementById(id); try { if (flvPlayer != null) { closePlayer(); } flvPlayer = flvjs.createPlayer({ type: 'flv', url: url, isLive: true, cors: true }, { enableWorker: true, enableStashBuffer: false, stashInitialSize: 1, fixAudioTimestampGap: false }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); setTimeout(function () { flvPlayer.play(); }, 150); timer = setInterval(function () { console.log('.'); if (flvPlayer.statisticsInfo.speed == 0) { console.log('reload1'); closePlayer(); playFlv(url); } else if (decodedFrames && flvPlayer.statisticsInfo.decodedFrames <= decodedFrames) { console.log('reload2'); closePlayer(); playFlv(url); } else if (flvPlayer.buffered.end(0) - flvPlayer.currentTime > 1) { console.log('reset currentTime'); flvPlayer.currentTime = flvPlayer.buffered.end(0) - 0.001; } decodedFrames = flvPlayer.statisticsInfo.decodedFrames; }, 10 * 1000); } catch (e) { console.log(e); } } function closePlayer() { if (timer) { clearInterval(timer); timer = null; } if (flvPlayer != null) { flvPlayer.pause(); flvPlayer.unload(); flvPlayer.detachMediaElement(); flvPlayer.destroy(); flvPlayer = null; } } function createChart() { $('canvas.chart').each(function () { var id = $(this).attr('id'); var canvas = document.getElementById(id); var label = $(this).attr('data-label'); var ctx = canvas.getContext('2d'); var config = createConfig(label, [], []); new Chart(ctx, config); }); } function createConfig(label, labels, data) { return { type: 'line', data: { labels: labels, datasets: [{ label: label, data: data, borderColor: 'green', fill: false }] }, options: { responsive: true, title: { display: true, text: label, } } }; } function updateChart() { var url = vm.IoTServer + '/App/Data?id='+device.Device.Id; $.getJSON(url, function (result) { console.log(result); $.each(result, function (i, n) { var id = n.id; Chart.helpers.each(Chart.instances, function (instance) { if (instance.chart.canvas.id == id) { console.log('update chart:' + id); instance.chart.data.labels = n.labels; instance.chart.data.datasets[0].data = n.data; instance.chart.update(); } }) }); }).fail(function () { console.log('error'); }).always(function () { app.dialog.close(); });; } Framework7.use(Framework7Vue); Vue.component('page-home', { template: '#page-home', data() { return { }; }, mounted() { }, methods: { } }); Vue.component('page-login', { template: '#page-login', data() { return { Server: localStorage.getItem('Server') ||'http://49.4.92.112:8000', UserName: localStorage.getItem('UserName'), Password: null, RememberMe: localStorage.getItem('RememberMe') }; }, mounted() { localStorage.removeItem('Token'); $('form.login').removeData('validator'); $('form.login').removeData('unobtrusiveValidation'); $.validator.unobtrusive.parse('form.login'); }, methods: { OnSubmit: function (e) { if (!$(e.target).valid()) { return; } var url = e.target.action; var data = $(e.target).serialize(); var current = this; $.post(url, data, function (response) { if (response.Code === 0) { vm.Token = response.Token; if (current.RememberMe === true) { localStorage.setItem("Token", response.Token); localStorage.setItem("Server", current.Server); localStorage.setItem("UserName", current.UserName); localStorage.setItem("NickName", response.NickName); localStorage.setItem("Title", response.Title); localStorage.setItem("IoTServer", _.trimEnd(response.IoTServer, ['/'])); } else { localStorage.removeItem("Token"); } vm.Server = current.Server; vm.RememberMe = current.RememberMe; vm.UserName = current.UserName; vm.NickName = response.NickName; vm.Title = response.Title; vm.IoTServer = _.trimEnd(response.IoTServer, ['/']); vm.$f7.view.current.router.back(); } else { app.dialog.alert(response.Message, "消息"); } }).fail(function (e) { var message; if (e.status === 0) { message = "不是有效的服务器地址"; } else { message = e.status + ":" + e.statusText; } vm.$f7.dialog.alert(message, "消息"); }); } } }); Vue.component('page-node', { template: '#page-node', data() { return { Node: { Number: null, Name: null, Sences: [], Devices: [] } } }, mounted() { this.Node.Number = this.$f7route.params.number; this.Node.Name = this.$f7route.params.name; node = this; var ajaxUrl = vm.IoTServer + "/App/GetNode?token=" + vm.Token + '&number=' + this.Node.Number; app.dialog.progress(); $.get(ajaxUrl, function (response) { node.Node = response; }).always(function () { app.dialog.close(); }); }, destroyed() { node = null; }, methods: { getData(device, dataName) { if (device != null) { var data = _.first(_.filter(device.Data, function (o) { return o.Name === dataName })); if (data != null) { if (data.Value) { var value = data.Value; if (data.Unit) { value += " " + data.Unit; } if (data.Description) { value += " " + data.Description; } return value; } else { console.log('值为空:' + device.Name + '/' + dataName); } } else { console.log('无法找到:' + device.Name + '/' + dataName); } } else { console.log('无法找到:' + dataName); } return ""; }, getDevices: function () { var args = arguments; return _.chain(this.Node.Devices).filter(function (device) { return _.chain(args).filter(function (name) { return device.Name.indexOf(name) != -1; }).value().length > 0; }).orderBy(['DisplayOrder', 'Name']).value(); }, callSence(id) { var url = vm.IoTServer + '/App/Sence/?node=' + this.Node.Number + '&id=' + id; ajax(url); }, call: function (id, cmd, query) { query = query || ''; var url = vm.IoTServer + '/App/Exec/?connectionId=' + connectionId + '&node=' + this.Node.Number + '&cmd=' + cmd + '&id=' + id; if (query != '') { url += "&" + query; } ajax(url); }, callAll: function (name, cmd, query) { query = query || ''; var url = vm.IoTServer + '/App/ExecAll/?connectionId=' + connectionId + '&node=' + this.Node.Number + '&cmd=' + cmd; var list = this.getDevices(name); for (var i = 0; i < list.length; i++) { url += '&id[' + i + ']=' + list[i].Id; } if (query != '') { url += "&" + query; } ajax(url); } } }); Vue.component('page-device', { template: '#page-device', data() { return { Device: { Number: null, Name: null, Data: [], Apis: [] } } }, mounted() { this.Device.Number = this.$f7route.params.number; this.Device.Name = this.$f7route.params.name; device = this; var ajaxUrl = vm.IoTServer + "/App/GetDevice?token=" + vm.Token + '&number=' + this.Device.Number; app.dialog.progress(); $.get(ajaxUrl, function (response) { device.Device = response; Vue.nextTick(function () { createChart(); updateChart(); $('form.command').removeData('validator'); $('form.command').removeData('unobtrusiveValidation'); $.validator.unobtrusive.parse('form.command'); }); }).always(function () { app.dialog.close(); }); }, methods: { isSelect: function (device, key) { return _.filter(device.Data, function (o) { return o.Key == key + '[]' }).length > 0; }, getSelect: function (device, key) { var data = _.first(_.filter(device.Data, function (o) { return o.Key == key + '[]' })).Value; var result = JSON.parse(data); return result; }, getParameter: function (name) { console.log(name); var prop = _.chain(this.Device.Data).filter(function (o) { return o.Key == name; }).first().value(); return prop ? prop.Value : ''; }, call: function (e) { if (!$(e.target).valid()) { return; } var url = vm.IoTServer + '/App/Exec/?connectionId=' + connectionId + '&node=' + this.getNodeNumber(this.Device.NodeId)+'&' + $(e.target).serialize(); ajax(url); }, getNodeNumber(nodeId) { return _.chain(vm.Nodes).filter(function (o) { return o.Id === nodeId; }).first().value().Number; }, showData(name) { if (name === 'hidden' || name.indexOf('rtsp') != -1 || name.indexOf('rtmp') != -1 || name.indexOf('flv') != -1 || name.indexOf('hls') != -1) { return false; } return true; }, showApi(api) { if (this.Device.Name === '摄像头') { if (this.getParameter('Ptz3DZoomSupport') === '否') { if (api.Name !== '截屏') { return false; } } } return true; }, getUrl(type) { var url = _.chain(this.Device.Data).filter(function (o) { return o.Name === (type + '2'); }).first().value().Value; url += '?id=' + this.Device.Id; url += '&host=' + encodeURIComponent(vm.IoTServer); url += '&node=' + _.chain(vm.Nodes).filter(function (o) { return o.Id === device.Device.NodeId; }).first().value().Number; if (this.getParameter('Ptz3DZoomSupport') !== '否') { url += '&ptz=true'; } return url; }, flv() { this.$f7router.navigate('/camera/', { props: { name: this.Device.DisplayName || this.Device.Name, url: this.getParameter('flv2'), ptz: this.getParameter('Ptz3DZoomSupport') !== '否', node: this.getNodeNumber(this.Device.NodeId), id: this.Device.Id, hls: this.getParameter('hls2') } }); } }, destroyed() { device = null; }, }); Vue.component('page-camera', { template: '#page-camera', props:['name','url','ptz','node','id','hls'], data() { return { } }, mounted() { this.play(); }, methods: { play: function () { var url = this.$props.url; if (isiOS) { $('#flvPlayer').attr('src', this.$props.hls); } else { playFlv(url); } }, call: function (cmd) { console.log(cmd); var url = vm.IoTServer + '/App/Exec/?connectionId=' + connectionId + '&cmd=' + cmd + '&node=' + this.$props.node + '&id=' + this.$props.id; ajax(url); return false; } }, destroy() { closePlayer(); } }); Vue.component('page-not-found', { template: '#page-not-found' }); vm = new Vue({ el: '#app', data() { return { f7params: { root: '#app', id: 'io.framework7.testapp', name: 'Framework7', theme: 'ios', routes: [ { path: '/', component: 'page-home' }, { path: '/login/', component: 'page-login' }, { path: '/node/:number/name/:name', component: 'page-node' }, { path: '/device/:number/name/:name', component: 'page-device' }, { path: '/camera/', component: 'page-camera' }, { path: '(.*)', component: 'page-not-found', }, ], }, Title: localStorage.getItem('Title'), Server: localStorage.getItem('Server'), Token: localStorage.getItem('Token'), UserName: localStorage.getItem('UserName'), RememberMe: localStorage.getItem('RememberMe'), NickName: localStorage.getItem('NickName'), IoTServer: localStorage.getItem('IoTServer'), User: null, Nodes: [], Messages: [], } }, mounted() { this.$f7ready((f7) => { app = this.$f7; if (this.Token) { this.init(); } else { setTimeout(function () { app.view.current.router.navigate('/login/') }, 0); } }); }, methods: { init() { if (this.Token) { var baseUrl = this.IoTServer; var wsUrl = baseUrl + "/hub?group=page"; var ajaxUrl = baseUrl + "/App/GetNodes?token=" + this.Token; $.get(ajaxUrl, function (response) { vm.Nodes = response; }); connection = new signalR.HubConnectionBuilder().withUrl(wsUrl).build(); onMessage(); connect(); } } } });