Browse Source

Merge pull request #14 from lawrencehj/wvp-28181-2.0

修正上级注册的代码
pull/15/head
648540858 4 years ago
committed by GitHub
parent
commit
bc2e5e7a37
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
  2. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  3. 16
      src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java
  4. 662
      web_src/src/components/platformEdit.vue

12
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java

@ -173,7 +173,7 @@ public class SIPRequestHeaderProvider {
} }
public Request createRegisterRequest(@NotNull ParentPlatform platform, String fromTag, String viaTag) throws ParseException, InvalidArgumentException, PeerUnavailableException { public Request createRegisterRequest(@NotNull ParentPlatform platform, long CSeq, String fromTag, String viaTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null; Request request = null;
String sipAddress = sipConfig.getSipIp() + ":" + sipConfig.getSipPort(); String sipAddress = sipConfig.getSipIp() + ":" + sipConfig.getSipPort();
//请求行 //请求行
@ -206,7 +206,7 @@ public class SIPRequestHeaderProvider {
MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70); MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
//ceq //ceq
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.REGISTER); CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(CSeq, Request.REGISTER);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.REGISTER, callIdHeader, request = sipFactory.createMessageFactory().createRequest(requestLine, Request.REGISTER, callIdHeader,
cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
@ -214,12 +214,15 @@ public class SIPRequestHeaderProvider {
.createSipURI(platform.getDeviceGBId(), sipAddress)); .createSipURI(platform.getDeviceGBId(), sipAddress));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
ExpiresHeader expires = sipFactory.createHeaderFactory().createExpiresHeader(3600);
request.addHeader(expires);
return request; return request;
} }
public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String viaTag, public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String viaTag,
String callId, String realm, String nonce, String scheme) throws ParseException, PeerUnavailableException, InvalidArgumentException { String callId, String realm, String nonce, String scheme) throws ParseException, PeerUnavailableException, InvalidArgumentException {
Request registerRequest = createRegisterRequest(parentPlatform, fromTag, viaTag); Request registerRequest = createRegisterRequest(parentPlatform, 2L, fromTag, viaTag);
CallIdHeader callIdHeader = (CallIdHeader)registerRequest.getHeader(CallIdHeader.NAME); CallIdHeader callIdHeader = (CallIdHeader)registerRequest.getHeader(CallIdHeader.NAME);
callIdHeader.setCallId(callId); callIdHeader.setCallId(callId);
@ -233,8 +236,7 @@ public class SIPRequestHeaderProvider {
String RESPONSE = DigestUtils.md5DigestAsHex((HA1 + ":" + nonce + ":" + HA2).getBytes()); String RESPONSE = DigestUtils.md5DigestAsHex((HA1 + ":" + nonce + ":" + HA2).getBytes());
String authorizationHeaderContent = scheme + " username=\"" + parentPlatform.getDeviceGBId() + "\", " + "realm=\"" String authorizationHeaderContent = scheme + " username=\"" + parentPlatform.getDeviceGBId() + "\", " + "realm=\""
+ realm + "\", uri=\"" + uri + "\", response=\"" + RESPONSE + "\", nonce=\"" + realm + "\", nonce=\"" + nonce + "\", uri=\"" + uri + "\", response=\"" + RESPONSE + "\"" + ", algorithm=MD5";
+ nonce + "\"";
AuthorizationHeader authorizationHeader = sipFactory.createHeaderFactory().createAuthorizationHeader(authorizationHeaderContent); AuthorizationHeader authorizationHeader = sipFactory.createHeaderFactory().createAuthorizationHeader(authorizationHeaderContent);
registerRequest.addHeader(authorizationHeader); registerRequest.addHeader(authorizationHeader);

2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@ -52,7 +52,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
try { try {
Request request = null; Request request = null;
if (realm == null || nonce == null) { if (realm == null || nonce == null) {
request = headerProvider.createRegisterRequest(parentPlatform, null, null); request = headerProvider.createRegisterRequest(parentPlatform, 1L, null, null);
}else { }else {
request = headerProvider.createRegisterRequest(parentPlatform, null, null, callId, realm, nonce, scheme); request = headerProvider.createRegisterRequest(parentPlatform, null, null, callId, realm, nonce, scheme);
} }

16
src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.vmanager.platform; package com.genersoft.iot.vmp.vmanager.platform;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.PageResult; import com.genersoft.iot.vmp.common.PageResult;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
@ -15,6 +16,8 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import com.genersoft.iot.vmp.conf.SipConfig;
@CrossOrigin @CrossOrigin
@RestController @RestController
@ -29,6 +32,19 @@ public class PlatformController {
@Autowired @Autowired
private ISIPCommanderForPlatform commanderForPlatform; private ISIPCommanderForPlatform commanderForPlatform;
@Autowired
private SipConfig sipConfig;
@GetMapping("/platforms/serverconfig")
public ResponseEntity<JSONObject> serverConfig() {
JSONObject result = new JSONObject();
result.put("deviceIp", sipConfig.getSipIp());
result.put("devicePort", sipConfig.getSipPort());
result.put("username", sipConfig.getSipId());
result.put("password", sipConfig.getSipPassword());
return new ResponseEntity<>(result, HttpStatus.OK);
}
@GetMapping("/platforms/{count}/{page}") @GetMapping("/platforms/{count}/{page}")
public PageResult<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count){ public PageResult<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count){

662
web_src/src/components/platformEdit.vue

@ -1,410 +1,418 @@
<template> <template>
<div id="addlatform" v-loading="isLoging"> <div id="addlatform" v-loading="isLoging">
<el-dialog title="添加平台" width="70%" top="2rem" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()"> <el-dialog
<div id="shared" style="text-align: right; margin-top: 1rem;"> title="添加平台"
width="70%"
<el-row :gutter="24"> top="2rem"
<el-col :span="11"> :close-on-click-modal="false"
<el-form ref="platform1" :rules="rules" :model="platform" label-width="160px" > :visible.sync="showDialog"
<el-form-item label="名称" prop="name"> :destroy-on-close="true"
<el-input v-model="platform.name"></el-input> @close="close()"
</el-form-item> >
<el-form-item label="SIP服务国标编码" prop="serverGBId"> <div id="shared" style="text-align: right; margin-top: 1rem">
<el-input v-model="platform.serverGBId" clearable></el-input> <el-row :gutter="24">
</el-form-item> <el-col :span="11">
<el-form-item label="SIP服务国标域" prop="serverGBDomain"> <el-form ref="platform1" :rules="rules" :model="platform" label-width="160px">
<el-input v-model="platform.serverGBDomain" clearable></el-input> <el-form-item label="名称" prop="name">
</el-form-item> <el-input v-model="platform.name"></el-input>
<el-form-item label="SIP服务IP" prop="serverIP"> </el-form-item>
<el-input v-model="platform.serverIP" clearable></el-input> <el-form-item label="SIP服务国标编码" prop="serverGBId">
</el-form-item> <el-input v-model="platform.serverGBId" clearable></el-input>
<el-form-item label="SIP服务端口" prop="serverPort"> </el-form-item>
<el-input v-model="platform.serverPort" clearable></el-input> <el-form-item label="SIP服务国标域" prop="serverGBDomain">
</el-form-item> <el-input v-model="platform.serverGBDomain" clearable></el-input>
<el-form-item label="设备国标编号" prop="deviceGBId"> </el-form-item>
<el-input v-model="platform.deviceGBId" clearable></el-input> <el-form-item label="SIP服务IP" prop="serverIP">
</el-form-item> <el-input v-model="platform.serverIP" clearable></el-input>
<el-form-item label="本地IP" prop="deviceIp"> </el-form-item>
<el-input v-model="platform.deviceIp" :disabled="true"></el-input> <el-form-item label="SIP服务端口" prop="serverPort">
</el-form-item> <el-input v-model="platform.serverPort" clearable></el-input>
<el-form-item label="本地端口" prop="devicePort"> </el-form-item>
<el-input v-model="platform.devicePort" :disabled="true"></el-input> <el-form-item label="设备国标编号" prop="deviceGBId">
</el-form-item> <el-input v-model="platform.deviceGBId" clearable></el-input>
</el-form-item>
</el-form> <el-form-item label="本地IP" prop="deviceIp">
</el-col> <el-input v-model="platform.deviceIp" :disabled="true"></el-input>
<el-col :span="12"> </el-form-item>
<el-form ref="platform2" :rules="rules" :model="platform" label-width="160px"> <el-form-item label="本地端口" prop="devicePort">
<el-form-item label="SIP认证用户名" prop="username"> <el-input v-model="platform.devicePort" :disabled="true"></el-input>
<el-input v-model="platform.username"></el-input> </el-form-item>
</el-form-item> </el-form>
<el-form-item label="SIP认证密码" prop="password"> </el-col>
<el-input v-model="platform.password" type="password"></el-input> <el-col :span="12">
</el-form-item> <el-form ref="platform2" :rules="rules" :model="platform" label-width="160px">
<el-form-item label="注册周期(秒)" prop="expires"> <el-form-item label="SIP认证用户名" prop="username">
<el-input v-model="platform.expires"></el-input> <el-input v-model="platform.username"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="心跳周期(秒)" prop="keepTimeout"> <el-form-item label="SIP认证密码" prop="password">
<el-input v-model="platform.keepTimeout"></el-input> <el-input v-model="platform.password" type="password"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="信令传输" prop="transport"> <el-form-item label="注册周期(秒)" prop="expires">
<el-select v-model="platform.transport" style="width:100%" placeholder="请选择信令传输方式"> <el-input v-model="platform.expires"></el-input>
<el-option label="UDP" value="UDP"></el-option> </el-form-item>
<el-option label="TCP" value="TCP"></el-option> <el-form-item label="心跳周期(秒)" prop="keepTimeout">
</el-select> <el-input v-model="platform.keepTimeout"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="字符集" prop="characterSet"> <el-form-item label="信令传输" prop="transport">
<el-select v-model="platform.characterSet" style="width:100%" placeholder="请选择字符集"> <el-select
<el-option label="GB2312" value="GB2312"></el-option> v-model="platform.transport"
<el-option label="UTF-8" value="UTF-8"></el-option> style="width: 100%"
</el-select> placeholder="请选择信令传输方式"
</el-form-item> >
<el-form-item label="其他选项" > <el-option label="UDP" value="UDP"></el-option>
<el-checkbox label="启用" v-model="platform.enable" ></el-checkbox> <el-option label="TCP" value="TCP"></el-option>
<el-checkbox label="云台控制" v-model="platform.PTZEnable"></el-checkbox> </el-select>
<el-checkbox label="RTCP保活" v-model="platform.rtcp"></el-checkbox> </el-form-item>
</el-form-item> <el-form-item label="字符集" prop="characterSet">
<el-form-item> <el-select
<el-button type="primary" @click="onSubmit">{{onSubmit_text}}</el-button> v-model="platform.characterSet"
<el-button @click="close">取消</el-button> style="width: 100%"
</el-form-item> placeholder="请选择字符集"
</el-form> >
</el-col> <el-option label="GB2312" value="GB2312"></el-option>
</el-row> <el-option label="UTF-8" value="UTF-8"></el-option>
</div> </el-select>
</el-form-item>
<el-form-item label="其他选项">
<el-checkbox label="启用" v-model="platform.enable"></el-checkbox>
<el-checkbox label="云台控制" v-model="platform.PTZEnable"></el-checkbox>
<el-checkbox label="RTCP保活" v-model="platform.rtcp"></el-checkbox>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">{{
onSubmit_text
}}</el-button>
<el-button @click="close">取消</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'platformEdit', name: "platformEdit",
props: {}, props: {},
computed: { computed: {},
created() {},
data() {
var deviceGBIdRules = async (rule, value, callback) => {
console.log(value);
if (value === "") {
callback(new Error("请输入设备国标编号"));
} else {
var exit = await this.deviceGBIdExit(value);
console.log(exit);
console.log(exit == "true");
console.log(exit === "true");
if (exit) {
callback(new Error("设备国标编号已存在"));
} else {
callback();
}
}
};
return {
listChangeCallback: null,
showDialog: false,
isLoging: false,
onSubmit_text: "立即创建",
// platform: {
// enable: false,
// PTZEnable: true,
// rtcp: false,
// name: null,
// serverGBId: null,
// serverGBDomain: null,
// serverIP: null,
// serverPort: null,
// deviceGBId: null,
// deviceIp: null,
// devicePort: null,
// username: null,
// password: null,
// expires: 300,
// keepTimeout: 60,
// transport: "UDP",
// characterSet: "GB2312",
// },
platform: {
enable: true,
PTZEnable: true,
rtcp: false,
name: "测试001",
serverGBId: "34020000002000000001",
serverGBDomain: "3402000000",
serverIP: "192.168.1.141",
serverPort: "5060",
deviceGBId: "34020000001320001101",
deviceIp: "192.168.1.20",
devicePort: "5060",
username: "34020000001320001101",
password: "12345678",
expires: 300,
keepTimeout: 60,
transport: "UDP",
characterSet: "GB2312",
},
rules: {
name: [{ required: true, message: "请输入平台名称", trigger: "blur" }],
serverGBId: [
{ required: true, message: "请输入SIP服务国标编码", trigger: "blur" },
],
serverGBDomain: [
{ required: true, message: "请输入SIP服务国标域", trigger: "blur" },
],
serverIP: [{ required: true, message: "请输入SIP服务IP", trigger: "blur" }],
serverPort: [{ required: true, message: "请输入SIP服务端口", trigger: "blur" }],
deviceGBId: [{ validator: deviceGBIdRules, trigger: "blur" }],
username: [{ required: false, message: "请输入SIP认证用户名", trigger: "blur" }],
password: [{ required: false, message: "请输入SIP认证密码", trigger: "blur" }],
expires: [{ required: true, message: "请输入注册周期", trigger: "blur" }],
keepTimeout: [{ required: true, message: "请输入心跳周期", trigger: "blur" }],
transport: [{ required: true, message: "请选择信令传输", trigger: "blur" }],
characterSet: [{ required: true, message: "请选择编码字符集", trigger: "blur" }],
},
};
},
methods: {
openDialog: function (platform, callback) {
var that = this;
this.$axios
.get(`/api/platforms/serverconfig`)
.then(function (res) {
console.log(res);
that.platform.deviceGBId = res.data.username;
that.platform.deviceIp = res.data.deviceIp;
that.platform.devicePort = res.data.devicePort;
that.platform.username = res.data.username;
that.platform.password = res.data.password;
})
.catch(function (error) {
console.log(error);
});
this.showDialog = true;
this.listChangeCallback = callback;
if (platform != null) {
this.platform = platform;
this.onSubmit_text = "保存";
} else {
}
}, },
created() {}, onSubmit: function () {
data() { console.log("onSubmit");
var deviceGBIdRules = async (rule, value, callback) => { var that = this;
console.log(value) that.$axios
if (value === '') { .post(`/api/platforms/save`, that.platform)
callback(new Error('请输入设备国标编号')); .then(function (res) {
} else { console.log(res);
var exit = await this.deviceGBIdExit(value); console.log(res.data == "success");
console.log(exit) if (res.data == "success") {
console.log(exit == "true") that.$message({
console.log(exit === "true") showClose: true,
if (exit) { message: "保存成功",
callback(new Error('设备国标编号已存在')); type: "success",
}else { });
callback(); that.showDialog = false;
if (that.listChangeCallback != null) {
that.listChangeCallback();
} }
} }
}; })
return { .catch(function (error) {
listChangeCallback: null, console.log(error);
showDialog: false, });
isLoging: false,
onSubmit_text:"立即创建",
// platform: {
// enable: false,
// PTZEnable: true,
// rtcp: false,
// name: null,
// serverGBId: null,
// serverGBDomain: null,
// serverIP: null,
// serverPort: null,
// deviceGBId: null,
// deviceIp: null,
// devicePort: null,
// username: null,
// password: null,
// expires: 300,
// keepTimeout: 60,
// transport: "UDP",
// characterSet: "GB2312",
// },
platform: {
enable: true,
PTZEnable: true,
rtcp: false,
name: "测试001",
serverGBId: "34020000002000000001",
serverGBDomain: "3402000000",
serverIP: "192.168.1.141",
serverPort: "5060",
deviceGBId: "34020000001320001101",
deviceIp: "192.168.1.20",
devicePort: "5060",
username: "34020000001320001101",
password: "12345678",
expires: 300,
keepTimeout: 60,
transport: "UDP",
characterSet: "GB2312",
},
rules: {
name: [
{ required: true, message:"请输入平台名称", trigger: 'blur' }
],
serverGBId: [
{ required: true, message:"请输入SIP服务国标编码", trigger: 'blur' }
],
serverGBDomain: [
{ required: true, message:"请输入SIP服务国标域", trigger: 'blur' }
],
serverIP: [
{ required: true, message:"请输入SIP服务IP", trigger: 'blur' }
],
serverPort: [
{ required: true, message:"请输入SIP服务端口", trigger: 'blur' }
],
deviceGBId: [
{validator: deviceGBIdRules, trigger: 'blur' }
],
username: [
{ required: false, message:"请输入SIP认证用户名", trigger: 'blur' }
],
password: [
{ required: false, message:"请输入SIP认证密码", trigger: 'blur' }
],
expires: [
{ required: true, message:"请输入注册周期", trigger: 'blur' }
],
keepTimeout: [
{ required: true, message:"请输入心跳周期", trigger: 'blur' }
],
transport: [
{ required: true, message:"请选择信令传输", trigger: 'blur' }
],
characterSet: [
{ required: true, message:"请选择编码字符集", trigger: 'blur' }
]
}
};
}, },
methods: { close: function () {
openDialog: function (platform, callback) { console.log("关闭添加视频平台");
this.showDialog = true; this.showDialog = false;
this.listChangeCallback = callback; this.$refs.platform1.resetFields();
if (platform != null) { this.$refs.platform2.resetFields();
this.platform = platform; },
this.onSubmit_text = "保存" deviceGBIdExit: async function (deviceGbId) {
} var result = false;
var that = this;
}, await that.$axios
onSubmit: function () { .post(`/api/platforms/exit/${deviceGbId}`)
console.log('onSubmit'); .then(function (res) {
var that = this; result = res.data;
that.$axios.post(`/api/platforms/save`, that.platform) })
.then(function (res) { .catch(function (error) {
console.log(res) console.log(error);
console.log(res.data == "success") });
if (res.data == "success") { return result;
that.$message({ },
showClose: true, },
message: '保存成功',
type: 'success'
});
that.showDialog = false;
if (that.listChangeCallback != null) {
that.listChangeCallback()
}
}
})
.catch(function (error) {
console.log(error);
});
},
close: function () {
console.log('关闭添加视频平台');
this.showDialog = false;
this.$refs.platform1.resetFields();
this.$refs.platform2.resetFields();
},
deviceGBIdExit: async function (deviceGbId) {
var result = false;
var that = this
await that.$axios.post(`/api/platforms/exit/${deviceGbId}`)
.then(function (res) {
result = res.data;
})
.catch(function (error) {
console.log(error);
});
return result;
}
}
}; };
</script> </script>
<style> <style>
.control-wrapper { .control-wrapper {
position: relative; position: relative;
width: 6.25rem; width: 6.25rem;
height: 6.25rem; height: 6.25rem;
max-width: 6.25rem; max-width: 6.25rem;
max-height: 6.25rem; max-height: 6.25rem;
border-radius: 100%; border-radius: 100%;
margin-top: 2.5rem; margin-top: 2.5rem;
margin-left: 0.5rem; margin-left: 0.5rem;
float: left; float: left;
} }
.control-panel { .control-panel {
position: relative; position: relative;
top: 0; top: 0;
left: 5rem; left: 5rem;
height: 11rem; height: 11rem;
max-height: 11rem; max-height: 11rem;
} }
.control-btn { .control-btn {
display: flex; display: flex;
justify-content: center; justify-content: center;
position: absolute; position: absolute;
width: 44%; width: 44%;
height: 44%; height: 44%;
border-radius: 5px; border-radius: 5px;
border: 1px solid #78aee4; border: 1px solid #78aee4;
box-sizing: border-box; box-sizing: border-box;
transition: all 0.3s linear; transition: all 0.3s linear;
} }
.control-btn i { .control-btn i {
font-size: 20px; font-size: 20px;
color: #78aee4; color: #78aee4;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.control-round { .control-round {
position: absolute; position: absolute;
top: 21%; top: 21%;
left: 21%; left: 21%;
width: 58%; width: 58%;
height: 58%; height: 58%;
background: #fff; background: #fff;
border-radius: 100%; border-radius: 100%;
} }
.control-round-inner { .control-round-inner {
position: absolute; position: absolute;
left: 13%; left: 13%;
top: 13%; top: 13%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 70%; width: 70%;
height: 70%; height: 70%;
font-size: 40px; font-size: 40px;
color: #78aee4; color: #78aee4;
border: 1px solid #78aee4; border: 1px solid #78aee4;
border-radius: 100%; border-radius: 100%;
transition: all 0.3s linear; transition: all 0.3s linear;
} }
.control-inner-btn { .control-inner-btn {
position: absolute; position: absolute;
width: 60%; width: 60%;
height: 60%; height: 60%;
background: #fafafa; background: #fafafa;
} }
.control-top { .control-top {
top: -8%; top: -8%;
left: 27%; left: 27%;
transform: rotate(-45deg); transform: rotate(-45deg);
border-radius: 5px 100% 5px 0; border-radius: 5px 100% 5px 0;
} }
.control-top i { .control-top i {
transform: rotate(45deg); transform: rotate(45deg);
border-radius: 5px 100% 5px 0; border-radius: 5px 100% 5px 0;
} }
.control-top .control-inner { .control-top .control-inner {
left: -1px; left: -1px;
bottom: 0; bottom: 0;
border-top: 1px solid #78aee4; border-top: 1px solid #78aee4;
border-right: 1px solid #78aee4; border-right: 1px solid #78aee4;
border-radius: 0 100% 0 0; border-radius: 0 100% 0 0;
} }
.control-top .fa { .control-top .fa {
transform: rotate(45deg) translateY(-7px); transform: rotate(45deg) translateY(-7px);
} }
.control-left { .control-left {
top: 27%; top: 27%;
left: -8%; left: -8%;
transform: rotate(45deg); transform: rotate(45deg);
border-radius: 5px 0 5px 100%; border-radius: 5px 0 5px 100%;
} }
.control-left i { .control-left i {
transform: rotate(-45deg); transform: rotate(-45deg);
} }
.control-left .control-inner { .control-left .control-inner {
right: -1px; right: -1px;
top: -1px; top: -1px;
border-bottom: 1px solid #78aee4; border-bottom: 1px solid #78aee4;
border-left: 1px solid #78aee4; border-left: 1px solid #78aee4;
border-radius: 0 0 0 100%; border-radius: 0 0 0 100%;
} }
.control-left .fa { .control-left .fa {
transform: rotate(-45deg) translateX(-7px); transform: rotate(-45deg) translateX(-7px);
} }
.control-right { .control-right {
top: 27%; top: 27%;
right: -8%; right: -8%;
transform: rotate(45deg); transform: rotate(45deg);
border-radius: 5px 100% 5px 0; border-radius: 5px 100% 5px 0;
} }
.control-right i { .control-right i {
transform: rotate(-45deg); transform: rotate(-45deg);
} }
.control-right .control-inner { .control-right .control-inner {
left: -1px; left: -1px;
bottom: -1px; bottom: -1px;
border-top: 1px solid #78aee4; border-top: 1px solid #78aee4;
border-right: 1px solid #78aee4; border-right: 1px solid #78aee4;
border-radius: 0 100% 0 0; border-radius: 0 100% 0 0;
} }
.control-right .fa { .control-right .fa {
transform: rotate(-45deg) translateX(7px); transform: rotate(-45deg) translateX(7px);
} }
.control-bottom { .control-bottom {
left: 27%; left: 27%;
bottom: -8%; bottom: -8%;
transform: rotate(45deg); transform: rotate(45deg);
border-radius: 0 5px 100% 5px; border-radius: 0 5px 100% 5px;
} }
.control-bottom i { .control-bottom i {
transform: rotate(-45deg); transform: rotate(-45deg);
} }
.control-bottom .control-inner { .control-bottom .control-inner {
top: -1px; top: -1px;
left: -1px; left: -1px;
border-bottom: 1px solid #78aee4; border-bottom: 1px solid #78aee4;
border-right: 1px solid #78aee4; border-right: 1px solid #78aee4;
border-radius: 0 0 100% 0; border-radius: 0 0 100% 0;
} }
.control-bottom .fa { .control-bottom .fa {
transform: rotate(-45deg) translateY(7px); transform: rotate(-45deg) translateY(7px);
} }
</style> </style>

Loading…
Cancel
Save