You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iot/projects/IoTCenter/wwwroot/node.html

1068 lines
53 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<style>
.content-wrapper {
background-color: lightblue;
}
input.switch {
display: none;
}
label.switch {
display: inline-block;
width: 60px;
height: 30px;
border-radius: 30px;
}
label.switch.on {
background-color: green;
}
label.switch.off {
background-color: grey;
}
label.switch.on::before {
content: '';
display: block;
width: 30px;
height: 30px;
border-radius: 30px;
background-color: white;
position: absolute;
left: 0;
}
label.switch.off::after {
content: '';
display: block;
width: 30px;
height: 30px;
border-radius: 30px;
background-color: white;
position: absolute;
right: 0;
}
.danger {
color: red;
}
.normal {
color: green;
}
.ptz {
width: 100%;
}
.ptz td {
text-align: center;
height: 53px;
}
.ptz img, .control img {
cursor: pointer;
}
form .label1 {
display: inline-block;
padding-right: 5px;
line-height: 50px;
vertical-align: middle;
}
.ir label input {
display: none;
}
.ir td {
width: 11%;
text-align: center;
}
.keyboard {
table-layout: fixed;
}
label.button {
display: inline-block;
padding: 0 10px;
line-height: 30px;
background-color: cadetblue;
color: #FFF;
vertical-align: middle;
border-radius: 15px;
text-align: center;
}
input[type=range] {
padding: 0 10px;
-webkit-appearance: none;
height: 50px;
}
input[type=range]::-webkit-slider-runnable-track {
width: 300px;
height: 5px;
background: #ddd;
border: none;
border-radius: 3px;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
border: none;
height: 20px;
width: 20px;
border-radius: 30%;
background-color: #3d9970 !important;
margin-top: -6px;
}
input[type=range]:focus {
outline: none;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: #ccc;
}
canvas {
width: 100%;
height: 215px;
}
</style>
<div class="row">
<div class="col-md-12">
<div v-if="ViewModel" class="callout callout-success">
<h4>{{ViewModel.Name}}</h4>
</div>
</div>
</div>
<div class="row" v-if="ViewModel">
<div class="col-md-6">
<template v-if="HasDevices('摄像头')">
<div class="row">
<div class="col-md-12">
<div class="box box-solid">
<select class="form-control" id="camera" @change="CameraSelected">
<option v-for="c in GetCameras()" :value="c.Number">{{c.DisplayName||c.Name}}</option>
</select>
<div style="width:100%;height:186px;margin:0;padding:0;background:#000;">
<video id="flvPlayer" class="video" controls autoplay style="width:100%;max-width:100%;height:100%;"></video>
</div>
</div>
</div>
</div>
<div class="row" id="ptz">
<div class="col-md-12">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/ptz.png" style="height:16px;margin-right:10px;" />云台操作</h3>
</div>
<div class="box-body" style="height:178px;">
<table class="ptz">
<tr>
<td></td>
<td></td>
<td><img class="ajax camera Up" src="/images/up.png" /></td>
<td></td>
<td></td>
</tr>
<tr>
<td><img class="ajax camera Zoomin" src="/images/zoomin.png" /></td>
<td><img class="ajax camera Left" src="/images/left.png" /></td>
<td><img class="ajax camera Stop" src="/images/stop.png" /></td>
<td><img class="ajax camera Right" src="/images/right.png" /></td>
<td><img class="ajax camera Zoomout" src="/images/zoomout.png" /></td>
</tr>
<tr>
<td></td>
<td></td>
<td><img class="ajax camera Down" src="/images/down.png" /></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</template>
<template v-for="device in GetDevices('调色灯')">
<div class="row">
<div class="col-md-12">
<div class="box box-solid btns">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/light2.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</h3>
<div class="box-tools pull-right">
<img v-if="GetDataValue(device.Number,'状态')=='开'" @click="CallApi(device.Number,'/ColorLight/Off')" src="/images/on.png" />
<img v-if="GetDataValue(device.Number,'状态')=='关'" @click="CallApi(device.Number,'/ColorLight/On')" src="/images/off.png" />
</div>
</div>
<div class="box-body" style="height:178px;">
<form method="get" action="/App/Exec">
<input type="hidden" name="Number" :value="device.Number" />
<input type="hidden" name="Method" value="/ColorLight/SetBrightness" />
<div class="row">
<div class="col-md-2 col-xs-4">
<span class="label1">亮度</span>
</div>
<div class="col-md-10 col-xs-8">
<input @change="AjaxSubmit($event,device.Number,'亮度')" type="range" min="0" step="1" max="255" name="Brightness" :value="GetDataValue(device.Number,'亮度')" />
</div>
</div>
</form>
<form method="get" action="/App/Exec">
<input type="hidden" name="Number" :value="device.Number" />
<input type="hidden" name="Method" value="/ColorLight/SetColor" />
<div class="row">
<div class="col-md-2 col-xs-4">
<span class="label1">色调</span>
</div>
<div class="col-md-10 col-xs-8">
<input @change="AjaxSubmit($event,device.Number,'色调')" type="range" min="0" step="1" max="255" name="Hue" :value="GetDataValue(device.Number,'色调')" />
</div>
</div>
<div class="row">
<div class="col-md-2 col-xs-4">
<span class="label1">饱和度</span>
</div>
<div class="col-md-10 col-xs-8">
<input @change="AjaxSubmit($event,device.Number,'饱和度')" type="range" min="0" step="1" max="255" name="Saturation" :value="GetDataValue(device.Number,'饱和度')" />
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<template v-for="device in GetDevices('红外转发器')">
<div class="row">
<div class="col-md-12">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="header"><img src="/images/control.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</li>
<li class="active"><a href="#tab_1" data-toggle="tab">空调</a></li>
<li><a href="#tab_2" data-toggle="tab">电视</a></li>
<li><a href="#tab_3" data-toggle="tab">图影仪</a></li>
<li><a href="#tab_4" data-toggle="tab">机顶盒</a></li>
<li><a href="#tab_5" data-toggle="tab">自定义</a></li>
</ul>
<div class="tab-content" style="min-height:176px;">
<div class="tab-pane active" id="tab_1">
<form class="device ir type1" method="get" action="/App/Exec">
<input type="hidden" name="Number" :value="device.Number" />
<input type="hidden" name="Method" value="/Ir/Send" />
<input type="hidden" name="Type" value="1" />
<input type="hidden" name="Code" :value="GetDataValue(device.Number,'按键')" />
<div class="row">
<div class="col-md-2 col-xs-4"><lable style="line-height:40px;">电源</lable></div>
<div class="col-md-2 col-xs-8">
<div class="row" style="padding:5px 0">
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="power" type="radio" value="2" v-model="getCode1(GetDataValue(device.Number,'按键')).power" /></label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="power" type="radio" value="1" v-model="getCode1(GetDataValue(device.Number,'按键')).power" /></label>
</div>
</div>
<div class="col-md-2 col-xs-4"><lable style="line-height:40px;">模式</lable></div>
<div class="col-md-6 col-xs-8">
<div class="row" style="padding:5px 0">
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="pattern" type="radio" value="0" v-model="getCode1(GetDataValue(device.Number,'按键')).pattern" />制冷</label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="pattern" type="radio" value="120" v-model="getCode1(GetDataValue(device.Number,'按键')).pattern" />自动</label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="pattern" type="radio" value="240" v-model="getCode1(GetDataValue(device.Number,'按键')).pattern" />制热</label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="pattern" type="radio" value="360" v-model="getCode1(GetDataValue(device.Number,'按键')).pattern" />抽湿</label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="pattern" type="radio" value="480" v-model="getCode1(GetDataValue(device.Number,'按键')).pattern" />送风</label>
</div>
</div>
</div>
<div class="row">
<div class="col-md-2 col-xs-4"><span class="label1">温度</span></div>
<div class="col-md-10 col-xs-8">
<input @change="SendCode1($event)" name="temperature" type="range" step="1" min="1" max="15" :value="getCode1(GetDataValue(device.Number,'按键')).temperature" />
</div>
</div>
<div class="row">
<div class="col-md-2 col-xs-4"><lable style="line-height:40px;">风向</lable></div>
<div class="col-md-4 col-xs-8">
<div class="row" style="padding:5px 0">
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="direction" type="radio" value="0" v-model="getCode1(GetDataValue(device.Number,'按键')).direction" />任意</label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="direction" type="radio" value="60" v-model="getCode1(GetDataValue(device.Number,'按键')).direction" />手动</label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="direction" type="radio" value="75" v-model="getCode1(GetDataValue(device.Number,'按键')).direction" />自动</label>
</div>
</div>
<div class="col-md-2 col-xs-4"><lable style="line-height:40px;">风量</lable></div>
<div class="col-md-4 col-xs-8">
<div class="row" style="padding:5px 0">
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="wind" type="radio" value="0" v-model="getCode1(GetDataValue(device.Number,'按键')).wind" />自动</label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="wind" type="radio" value="15" v-model="getCode1(GetDataValue(device.Number,'按键')).wind" /></label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="wind" type="radio" value="30" v-model="getCode1(GetDataValue(device.Number,'按键')).wind" /></label>
<label class="btn btn-sm bg-olive"><input @change="SendCode1($event)" name="wind" type="radio" value="45" v-model="getCode1(GetDataValue(device.Number,'按键')).wind" /></label>
</div>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="tab_2">
</div>
<div class="tab-pane" id="tab_3">
</div>
<div class="tab-pane" id="tab_4">
</div>
<div class="tab-pane" id="tab_5">
</div>
</div>
</div>
</div>
</div>
</template>
</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-12">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/batch.png" style="height:16px;margin-right:10px;" />批量操作</h3>
<div class="box-tools pull-right">
<button class="btn btn-sm bg-olive ajax NodePowerOn" :data-node-number="ViewModel.Number">一键开</button>
<button class="btn btn-sm bg-olive ajax NodePowerOff" :data-node-number="ViewModel.Number">一键关</button>
</div>
</div>
<div class="box-body" style="height:178px;">
<button class="btn bg-olive margin ajax SwitchOn">开关开</button>
<button class="btn bg-olive margin ajax SwitchOff">开关关</button>
<button class="btn bg-olive margin ajax SocketOn">插座开</button>
<button class="btn bg-olive margin ajax SocketOff">插座关</button>
<br />
<button class="btn bg-olive margin ajax Scene" v-for="scene in ViewModel.Scenes" :data-node-number="ViewModel.Number" :data-scene-name="scene.Name">{{scene.Name}}</button>
</div>
</div>
</div>
</div>
<div class="row" v-for="device in GetDevices('粉尘检测器')" :data-device-number="device.Number">
<div class="col-md-6 col-xs-6">
<div class="box box-solid">
<div class="row">
<div class="col-md-4 col-xs-4">
<img src="/images/temperature.png" style="width:48px;height:48px;margin:19px;" />
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<h3 style="line-height:100px;margin:0;" :class="GetDeviceDataValue(device.Number,'温度','Description')==='适中'?'normal':'danger'">
{{GetDeviceDataValue(device.Number,'温度','Description')}}
</h3>
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<span style="display:inline-block;position:absolute;right:20px;bottom:5px;white-space: nowrap;">温度:{{GetDeviceDataValue(device.Number,'温度','Value')}}{{ GetDeviceDataValue(device.Number,'温度','Unit')}}</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xs-6">
<div class="box box-solid">
<div class="row">
<div class="col-md-4 col-xs-4">
<img src="/images/humidity.png" style="width:48px;height:48px;margin:19px;" />
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<h3 style="line-height:100px;margin:0;" :class="GetDeviceDataValue(device.Number,'湿度','Description')==='适中'?'normal':'danger'">
{{GetDeviceDataValue(device.Number,'湿度','Description')}}
</h3>
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<span style="display:inline-block;position:absolute;right:20px;bottom:5px;white-space: nowrap;">湿度:{{GetDeviceDataValue(device.Number,'湿度','Value')}}{{ GetDeviceDataValue(device.Number,'温度','Unit')}}</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xs-6">
<div class="box box-solid">
<div class="row">
<div class="col-md-4 col-xs-4">
<img src="/images/pm25.png" style="width:48px;height:48px;margin:19px;" />
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<h3 style="line-height:100px;margin:0;" :class="GetDeviceDataValue(device.Number,'PM2.5','Description')==='污染'?'danger':'normal'">
{{GetDeviceDataValue(device.Number,'PM2.5','Description')}}
</h3>
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<span style="display:inline-block;position:absolute;right:20px;bottom:5px;white-space: nowrap;">PM2.5{{GetDeviceDataValue(device.Number,'PM2.5','Value')}}{{ GetDeviceDataValue(device.Number,'PM2.5','Unit')}}</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xs-6">
<div class="box box-solid">
<div class="row">
<div class="col-md-4 col-xs-4">
<img src="/images/pm25.png" style="width:48px;height:48px;margin:19px;" />
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<h3 style="line-height:100px;margin:0;" :class="GetDeviceDataValue(device.Number,'PM10','Description')==='污染'?'danger':'normal'">
{{GetDeviceDataValue(device.Number,'PM10','Description')}}
</h3>
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<span style="display:inline-block;position:absolute;right:20px;bottom:5px;white-space: nowrap;">PM10{{GetDeviceDataValue(device.Number,'PM10','Value')}}{{ GetDeviceDataValue(device.Number,'PM10','Unit')}}</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xs-6" v-for="device in GetDevices('光强检测器')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="row">
<div class="col-md-4 col-xs-4">
<img src="/images/light.png" style="width:48px;height:48px;margin:19px;" />
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<h3 style="line-height:100px;margin:0;" :class="GetDeviceDataValue(device.Number,'光照度','Description')==='适中'?'normal':'danger'">
{{GetDeviceDataValue(device.Number,'光照度','Description')}}
</h3>
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<span style="display:inline-block;position:absolute;right:20px;bottom:5px;white-space: nowrap;">{{device.DisplayName||device.Name}} 光照 {{GetDeviceDataValue(device.Number,'光照度','Value')}}{{ GetDeviceDataValue(device.Number,'光照度','Unit')}}</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xs-6" v-for="device in GetDevices('红外感应器')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="row">
<div class="col-md-4 col-xs-4">
<img src="/images/person.png" style="width:48px;height:48px;margin:19px;" />
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<img src="/images/warn.png" style="width:36px;height:36px;margin:32px 0 0 0;" v-if="GetDeviceDataValue(device.Number,'状态','Value')==='警报'" />
<h3 style="line-height:100px;margin:0;" class="normal" v-else>正常</h3>
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<span style="display:inline-block;position:absolute;right:20px;bottom:5px;white-space: nowrap;">{{device.DisplayName||device.Name}} {{GetDeviceDataValue(device.Number,'状态','Value') }}</span>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-xs-6" v-for="device in GetDevices('烟雾传感器')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="row">
<div class="col-md-4 col-xs-4">
<img src="/images/smoke.png" style="width:48px;height:48px;margin:19px;" />
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<img src="/images/warn.png" style="width:36px;height:36px;margin:32px 0 0 0;" v-if="GetDeviceDataValue(device.Number,'状态','Value')==='警报'" />
<h3 style="line-height:100px;margin:0;" class="normal" v-else>正常</h3>
</div>
<div class="col-md-4 col-xs-4" style="height:100px;">
<span style="display:inline-block;position:absolute;right:20px;bottom:5px;white-space: nowrap;">{{device.DisplayName||device.Name}} {{GetDeviceDataValue(device.Number,'状态','Value') }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-xs-6 control" v-for="device in GetDevices('窗帘')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/curtain.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</h3>
<div class="box-tools pull-right">
{{GetDataValue(device.Number,'状态')}}
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="row" style="text-align:center;padding:3px 0;">
<img @click="CallApi(device.Number,'/Curtain/On')" src="/images/on.png" />
<img @click="CallApi(device.Number,'/Curtain/Stop')" src="/images/stop32.png" />
<img @click="CallApi(device.Number,'/Curtain/Off')" src="/images/off.png" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-xs-6 control" v-for="device in GetDevices('一路开关')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/switch.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="row" style="text-align:center;padding:3px 0;">
<img v-if="GetDataValue(device.Number,'L1状态')=='开'" @click="CallApi(device.Number,'/Switch/L1Off')" src="/images/on.png" />
<img v-if="GetDataValue(device.Number,'L1状态')=='关'" @click="CallApi(device.Number,'/Switch/L1On')" src="/images/off.png" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-xs-6 control" v-for="device in GetDevices('二路开关')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/switch.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</h3>
<div class="box-tools pull-right">
<button class="btn btn-sm bg-olive" @click="CallApi(device.Number,'/Switch3/On')" :data-node-number="ViewModel.Number">一键开</button>
<button class="btn btn-sm bg-olive" @click="CallApi(device.Number,'/Switch3/Off')" :data-node-number="ViewModel.Number">一键关</button>
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="row" style="text-align:center;padding:3px 0;">
<img v-if="GetDataValue(device.Number,'L1状态')=='开'" @click="CallApi(device.Number,'/Switch2/L1Off')" src="/images/on.png" />
<img v-if="GetDataValue(device.Number,'L1状态')=='关'" @click="CallApi(device.Number,'/Switch2/L1On')" src="/images/off.png" />
<img v-if="GetDataValue(device.Number,'L2状态')=='开'" @click="CallApi(device.Number,'/Switch2/L2Off')" src="/images/on.png" />
<img v-if="GetDataValue(device.Number,'L2状态')=='关'" @click="CallApi(device.Number,'/Switch2/L2On')" src="/images/off.png" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-xs-6 control" v-for="device in GetDevices('三路开关')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/switch2.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</h3>
<div class="box-tools pull-right">
<button class="btn btn-sm bg-olive" @click="CallApi(device.Number,'/Switch3/On')" :data-node-number="ViewModel.Number">一键开</button>
<button class="btn btn-sm bg-olive" @click="CallApi(device.Number,'/Switch3/Off')" :data-node-number="ViewModel.Number">一键关</button>
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="row" style="text-align:center;padding:3px 0;">
<img v-if="GetDataValue(device.Number,'L1状态')=='开'" @click="CallApi(device.Number,'/Switch3/L1Off')" src="/images/on.png" />
<img v-if="GetDataValue(device.Number,'L1状态')=='关'" @click="CallApi(device.Number,'/Switch3/L1On')" src="/images/off.png" />
<img v-if="GetDataValue(device.Number,'L2状态')=='开'" @click="CallApi(device.Number,'/Switch3/L2Off')" src="/images/on.png" />
<img v-if="GetDataValue(device.Number,'L2状态')=='关'" @click="CallApi(device.Number,'/Switch3/L2On')" src="/images/off.png" />
<img v-if="GetDataValue(device.Number,'L3状态')=='开'" @click="CallApi(device.Number,'/Switch3/L3Off')" src="/images/on.png" />
<img v-if="GetDataValue(device.Number,'L3状态')=='关'" @click="CallApi(device.Number,'/Switch3/L3On')" src="/images/off.png" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-xs-6 control" v-for="device in GetDevices('智能插座')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/socket.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</h3>
<div class="box-tools pull-right">
{{parseFloat(GetDataValue(device.Number,'电量')).toFixed(2)}} kWh
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="row" style="text-align:center;padding:3px 0;">
<img v-if="GetDataValue(device.Number,'状态')==='开'" @click="CallApi(device.Number,'/Socket/Off')" src="/images/on.png" :data-status="GetDataValue(device.Number,'状态')" />
<img v-if="GetDataValue(device.Number,'状态')==='关'" @click="CallApi(device.Number,'/Socket/On')" src="/images/off.png" :data-status="GetDataValue(device.Number,'状态')" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-xs-6 control" v-for="device in GetDevices('插座')" :data-device-number="device.Number">
<div class="box box-solid">
<div class="box-header with-border">
<h3 class="box-title"><img src="/images/socket.png" style="height:16px;margin-right:10px;" />{{device.DisplayName||device.Name}}</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="row" style="text-align:center;padding:3px 0;">
<img v-if="GetDataValue(device.Number,'状态')==='开'" @click="CallApi(device.Number,'/Socket/Off')" src="/images/on.png" :data-status="GetDataValue(device.Number,'状态')" />
<img v-if="GetDataValue(device.Number,'状态')==='关'" @click="CallApi(device.Number,'/Socket/On')" src="/images/off.png" :data-status="GetDataValue(device.Number,'状态')" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var connection;
var connectionId;
$.ajaxSetup({
cache: false,
timeout: 5000
});
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 Color16() {//十六进制颜色随机
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
var color = '#' + r.toString(16) + g.toString(16) + b.toString(16);
return color;
}
function ajax(url, data, type) {
console.log(url);
type = type || 'get';
$('.overlay').show();
$.ajax({
type: type,
url: url,
data: data,
success: AjaxCallBack
}).fail(function (result) {
console.log('error');
console.log(result);
}).always(function () {
$('.overlay').hide();
});
}
function AjaxCallBack(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('<img class="shot" src="' + result.data + '">');
}
else {
console.log('format/0/json object');
$('#callback .page-content').html(result.data);
}
app.popup.open('#callback');
}
}
}
</script>
<script>
function onMessage() {
connection.on('Connected', function (id) {
connectionId = id;
});
connection.on("UpdateDevice", (message) => {
var newDevice = JSON.parse(message);
if (newDevice.NodeId === vm.ViewModel.Id) {
var update = false;
for (var i = 0; i < vm.ViewModel.Devices.length; i++) {
if (vm.ViewModel.Devices[i].Number == newDevice.Number) {
update = true;
break;
}
}
if (update) {
vm.ViewModel.Devices.splice(i, 1, newDevice);
}
else {
vm.ViewModel.Devices.push(newDevice);
}
}
});
}
</script>
<script>
function UpdateChart(title, id, key, time) {
var number = $('#' + id).attr('data-device-number');
time = time || '30d';
var url = '/Home/GetChartData?number=' + number + '&key=' + key + '&time=' + time;
$.get(url, function (response) {
if (response) {
var ctx = document.getElementById(id).getContext('2d');
var data = {
datasets: [{
label: title,
data: response.data,
backgroundColor: Color16(),
fill: false
}],
labels: response.labels
};
var options = {
responsive: true,
legend: {
position: 'bottom',
},
title: {
display: true,
text: title
},
animation: {
duration: 0
}
};
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: options
});
}
});
}
</script>
<script>
$('body').on('click', 'button.ajax', function (e) {
var data = $.map($('.switch:checked').toArray(), function (o) { return $(o).attr('data-node-number'); });
if ($(this).hasClass('AllPowerOn')) {
ajax('/App/AllPowerOn', { nodes: data }, 'post');
} else if ($(this).hasClass('AllPowerOff')) {
ajax('/App/AllPowerOff', { nodes: data }, 'post');
} else if ($(this).hasClass('AllSwitchOn')) {
ajax('/App/AllSwitchOn', { nodes: data }, 'post');
} else if ($(this).hasClass('AllSwitchOff')) {
ajax('/App/AllSwitchOff', { nodes: data }, 'post');
} else if ($(this).hasClass('AllSocketOn')) {
ajax('/App/AllSocketOn', { nodes: data }, 'post');
} else if ($(this).hasClass('AllSocketOff')) {
ajax('/App/AllSocketOff', { nodes: data }, 'post');
} else if ($(this).hasClass('NodePowerOn')) {
ajax('/App/NodePowerOn', { node: $(this).attr('data-node-number') }, 'post');
} else if ($(this).hasClass('NodePowerOff')) {
ajax('/App/NodePowerOff', { node: $(this).attr('data-node-number') }, 'post');
} else if ($(this).hasClass('NodeSwitchOn')) {
ajax('/App/NodeSwitchOn', { node: $(this).attr('data-node-number') }, 'post');
} else if ($(this).hasClass('NodeSwitchOff')) {
ajax('/App/NodeSwitchOff', { node: $(this).attr('data-node-number') }, 'post');
} else if ($(this).hasClass('NodeSwitch3On')) {
ajax('/App/NodeSwitch3On', { node: $(this).attr('data-node-number') }, 'post');
} else if ($(this).hasClass('NodeSwitch3Off')) {
ajax('/App/NodeSwitch3Off', { node: $(this).attr('data-node-number') }, 'post');
}
else if ($(this).hasClass('NodeSocketOn')) {
ajax('/App/NodeSocketOn', { node: $(this).attr('data-node-number') }, 'post');
} else if ($(this).hasClass('NodeSocketOff')) {
ajax('/App/NodeSocketOff', { node: $(this).attr('data-node-number') }, 'post');
} else if ($(this).hasClass('Scene')) {
ajax('/App/Scene', { node: $(this).attr('data-node-number'), name: $(this).attr('data-scene-name') }, 'post');
}
return false;
});
$('body').on('mousedown touchstart', 'img.camera.ajax', function (e) {
var number = $('#camera').val();
if ($(this).hasClass('Zoomin')) {
ajax('/App/Exec', { connectionId: connectionId, number: number, method: '/Onvif/Zoomin' }, 'post');
} else if ($(this).hasClass('Zoomout')) {
ajax('/App/Exec', { connectionId: connectionId, number: number, method: '/Onvif/Zoomout' }, 'post');
} else if ($(this).hasClass('Left')) {
ajax('/App/Exec', { connectionId: connectionId, number: number, method: '/Onvif/Left' }, 'post');
} else if ($(this).hasClass('Right')) {
ajax('/App/Exec', { connectionId: connectionId, number: number, method: '/Onvif/Right' }, 'post');
} else if ($(this).hasClass('Up')) {
ajax('/App/Exec', { connectionId: connectionId, number: number, method: '/Onvif/Up' }, 'post');
} else if ($(this).hasClass('Down')) {
ajax('/App/Exec', { connectionId: connectionId, number: number, method: '/Onvif/Down' }, 'post');
} else if ($(this).hasClass('Stop')) {
ajax('/App/Exec', { connectionId: connectionId, number: number, method: '/Onvif/Stop' }, 'post');
}
return false;
});
$('body').on('mouseup touchend', 'img.ajax', function (e) {
console.log($(this).html());
if (!$(this).hasClass('Stop')) {
var number = $('#camera').val();
ajax('/App/Exec', { number: number, method: '/Onvif/Stop' }, 'post');
}
return false;
});
</script>
<script>
var flvPlayer;
var timer;
var decodedFrames;
$('body').on('change', '#camera', function (e) {
UpdateCamera()
});
function UpdateCamera() {
var number = $('#camera').val();
if (number) {
var device = Enumerable.from(vm.ViewModel.Devices).where(function (o) { return o.Number === number; }).firstOrDefault();
var url = Enumerable.from(device.Data).where(o => o.Name === '主码流flv').firstOrDefault().Value;
var hasPtz = Enumerable.from(device.Data).where(o => o.Name === '缩放支持').firstOrDefault().Value === '是';
if (hasPtz) {
$('#ptz').show();
}
else {
$('#ptz').hide();
}
closePlayer(flvPlayer);
playFlv(document.getElementById("flvPlayer"), url);
}
}
function playFlv(videoElement, url) {
try {
flvPlayer = flvjs.createPlayer({
type: 'flv',
url: url,
isLive: true,
cors: true
}, {
enableWorker: true,
enableStashBuffer: false,
stashInitialSize: 1,
fixAudioTimestampGap: false
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.muted = false;
timer = setInterval(function () {
console.log('.');
if (flvPlayer.statisticsInfo.speed == 0) {
console.log('reload1');
clearInterval(timer);
closePlayer(flvPlayer);
playFlv(videoElement, url);
}
else if (decodedFrames && flvPlayer.statisticsInfo.decodedFrames <= decodedFrames) {
console.log('reload2');
clearInterval(timer);
closePlayer(flvPlayer);
playFlv(videoElement, 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(flvPlayer) {
if (timer) {
clearInterval(timer);
}
if (flvPlayer != null) {
flvPlayer.pause();
flvPlayer.unload();
flvPlayer.detachMediaElement();
flvPlayer.destroy();
flvPlayer = null;
}
}
</script>
<script>
var vm = new Vue({
el: '#template',
data() {
return {
ViewModel: null
}
},
mounted() {
var url = '/Home/GetNode' + '?number=' + new URI().query(true).number;
$.get(url, function (data) {
vm.ViewModel = data;
var wsUrl = '/hub?group=page';
connection = new signalR.HubConnectionBuilder().withUrl(wsUrl).build();
onMessage();
connect();
Vue.nextTick(function () {
UpdateCamera();
//UpdateChart('温度', 'TemperatureChart', 'Temperature');
//UpdateChart('湿度', 'humidityChart', 'Humidity');
//UpdateChart('前门光照', 'LightChart1', 'Light');
//UpdateChart('后门光照', 'LightChart2', 'Light');
//UpdateChart('用电', 'EnergyChart', 'Electricity');
});
});
},
methods: {
GetData(deviceName, displayName, tag, dataName, attr) {
var query = Enumerable.from(vm.ViewModel.Devices).where(function (o) { return o.Name === deviceName; });
if (displayName != null) {
query = query.where(o => o.DisplayName === displayName);
}
if (tag != null) {
query = query.where(o => o.Tag === tag);
}
var device = query.firstOrDefault();
if (device) {
var data = Enumerable.from(device.Data).where(o => o.Name === dataName).firstOrDefault();
if (data != null) {
return data[attr];
}
}
return null;
},
HasDevices(name) {
return Enumerable
.from(vm.ViewModel.Devices)
.any(function (o) { return o.Name === name });
},
GetCameras() {
return Enumerable
.from(vm.ViewModel.Devices)
.where(function (o) { return o.Name === '摄像头' })
.toArray();
},
CameraSelected() {
console.log('camera selected:' + new Date());
UpdateCamera();
},
GetDevices(name) {
return Enumerable.from(vm.ViewModel.Devices)
.where(function (o) { return o.Name == name; })
.toArray();
},
GetDevice(name, tag) {
var query = Enumerable.from(vm.ViewModel.Devices);
if (name) {
query = query.where(function (o) { return o.Name === name; });
}
if (tag) {
query = query.where(function (o) { return o.Tag === tag; });
}
return query.firstOrDefault();
},
GetDeviceDataValue(number, name, attr) {
var device = Enumerable.from(vm.ViewModel.Devices).where(function (o) { return o.Number === number; }).firstOrDefault();
var data = Enumerable.from(device.Data).where(o => o.Name === name).firstOrDefault();
if (data != null) {
return data[attr];
}
return null;
},
GetDeviceNumber(name, tag) {
var device = vm.GetDevice(name, tag);
return device == null ? null : device.Number;
},
GetDataValue(number, name) {
var device = Enumerable.from(vm.ViewModel.Devices)
.where(function (o) { return o.Number === number; })
.firstOrDefault();
if (device != null) {
var data = Enumerable.from(device.Data)
.where(function (o) { return o.Name == name })
.firstOrDefault();
if (data != null) {
return data.Value;
}
}
return null;
},
CallApi(number, method, query) {
ajax('/App/Exec', { number: number, method: method, query: query }, 'post');
},
AjaxSubmit(event, deviceNumber, dataName) {
var device = Enumerable.from(vm.ViewModel.Devices)
.where(function (o) { return o.Number === deviceNumber; })
.firstOrDefault();
if (device != null) {
var data = Enumerable.from(device.Data)
.where(function (o) { return o.Name == dataName })
.firstOrDefault();
if (data != null) {
data.Value = $(event.target).val();
}
}
var form = $(event.target).parents('form');
var url = form.attr('action') + '?' + form.serialize();
Vue.nextTick(function () {
ajax(url, null, 'get');
});
},
getCode1(code) {
var pattern = 0;
var direction = 0;
var wind = 0;
var power = 2;
var temperature = 1;
if (code > 480 + 2) {
pattern = 480;
}
else if (code > 360 + 2) {
pattern = 360;
}
else if (code > 240 + 2) {
pattern = 240;
}
else if (code > 120 + 2) {
pattern = 120;
}
else {
pattern = 0;
}
code -= pattern;
if (code > 75 + 2) {
direction = 75;
}
else if (code > 60 + 2) {
direction = 60;
}
else {
direction = 0;
}
code -= direction;
if (code > 45 + 2) {
wind = 45;
}
else if (code > 30 + 2) {
wind = 30;
}
else if (code > 15 + 2) {
wind = 15;
}
else {
wind = 0;
}
code -= wind;
if (code === 1) {
power = 1;
}
else {
power = 2;
temperature = code - power;
}
return {
pattern: pattern,
direction: direction,
wind: wind,
power: power,
temperature: temperature
};
},
SendCode1(event) {
console.log(event.target);
var form = $(event.target).parents('form');
var url = form.attr('action') + '?' + form.serialize();
if (form.hasClass('type1')) {
if (event.target.name == "power" && event.target.value == "1") {
url = new URI(url).setQuery('Code', '1').toString();
}
else {
var list = {};
list['power'] = form.find("[name = 'power']:checked").val();
list['pattern'] = form.find("[name = 'pattern']:checked").val();
list['direction'] = form.find("[name = 'direction']:checked").val();
list['wind'] = form.find("[name = 'wind']:checked").val();
list['temperature'] = form.find("[name = 'temperature']").val();
list[event.target.name] = event.target.value;
var code = 0;
for (var name in list) {
code += parseInt(list[name]);
}
url = new URI(url).setQuery('Code', code).toString();
}
}
Vue.nextTick(function () {
ajax(url, null, 'get');
});
}
},
destroy() {
closePlayer();
}
});
</script>