ptzControl.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. <template>
  2. <div style="display: flex; justify-content: left;">
  3. <div class="control-mic">
  4. <microphone :channel-id="channelId" :device-id="deviceId" :enable-debug="enableDebug"
  5. :http-hook="httpHook"
  6. :https-hook="httpsHook"
  7. :push-key="pushKey"
  8. ></microphone>
  9. </div>
  10. <div class="control-wrapper">
  11. <div class="control-btn control-top" @mousedown="ptzControlHandleDown('up')" @mouseup="ptzControlHandleUp('up')">
  12. <i class="el-icon-caret-top"></i>
  13. <div class="control-inner-btn control-inner"></div>
  14. </div>
  15. <div class="control-btn control-left" @mousedown="ptzControlHandleDown('left')" @mouseup="ptzControlHandleUp('left')">
  16. <i class="el-icon-caret-left"></i>
  17. <div class="control-inner-btn control-inner"></div>
  18. </div>
  19. <div class="control-btn control-bottom" @mousedown="ptzControlHandleDown('down')" @mouseup="ptzControlHandleUp('down')">
  20. <i class="el-icon-caret-bottom"></i>
  21. <div class="control-inner-btn control-inner"></div>
  22. </div>
  23. <div class="control-btn control-right" @mousedown="ptzControlHandleDown('right')" @mouseup="ptzControlHandleUp('right')">
  24. <i class="el-icon-caret-right"></i>
  25. <div class="control-inner-btn control-inner"></div>
  26. </div>
  27. <div class="control-round">
  28. <div class="control-round-inner"><i class="fa fa-pause-circle"></i></div>
  29. </div>
  30. <!-- 放大 -->
  31. <div style="position: absolute; left: 7.25rem; top: -1.1rem" @mousedown="ptzCamera('zoomin')" @mouseup="ptzCamera('stop')"><i class="el-icon-zoom-in control-zoom-btn" style="font-size: 1.875rem;"></i></div>
  32. <!-- 聚焦 -->
  33. <div style="position: absolute; left: 7.25rem; top: 1.25rem"
  34. @click="ptzCameraFocus('focus')" >
  35. <i class="el-icon-aim control-zoom-btn" style="font-size: 1.875rem;"></i>
  36. </div>
  37. <!-- 缩小 -->
  38. <div style="position: absolute; left: 7.25rem; top: 3.25rem; font-size: 1.875rem;" @mousedown="ptzCamera('zoomout')" @mouseup="ptzCamera('stop')"><i class="el-icon-zoom-out control-zoom-btn"></i></div>
  39. <div class="contro-speed" style="position: absolute; left: 4px; top: 7rem; width: 9rem;">
  40. <el-slider v-model="controSpeed" :max="255"></el-slider>
  41. </div>
  42. </div>
  43. <div class="control-panel">
  44. <!-- 预置位 -->
  45. <el-tabs tab-position="left" style="height: 200px;">
  46. <el-tab-pane label="预置位">
  47. <!-- 预置位查询 -->
  48. <el-table
  49. v-loading="presetLoading"
  50. :data="presetList"
  51. height="100%"
  52. :row-style="{height: 30}"
  53. style="width: 100%;font-size: 16px">
  54. <el-table-column
  55. prop="ind"
  56. label="序号"
  57. width="90">
  58. </el-table-column>
  59. <el-table-column
  60. prop="remark"
  61. label="备注"
  62. width="100">
  63. </el-table-column>
  64. <el-table-column
  65. prop="operation">
  66. <template slot="header" slot-scope="scope">
  67. <el-button type="primary" size="mini" icon="el-icon-refresh" @click="queryPresetPos"></el-button>
  68. </template>
  69. </el-table-column>
  70. </el-table>
  71. </el-tab-pane>
  72. <!-- <el-tab-pane label="巡航">配置管理</el-tab-pane>-->
  73. <!-- <el-tab-pane label="扫描">角色管理</el-tab-pane>-->
  74. </el-tabs>
  75. <!-- <el-button-group>-->
  76. <!-- <el-tag style="position :absolute; left: 0rem; top: 0rem; width: 5rem; text-align: center" size="medium">预置位编号</el-tag>-->
  77. <!-- <el-input-number style="position: absolute; left: 5rem; top: 0rem; width: 6rem" size="mini" v-model="presetPos" controls-position="right" :precision="0" :step="1" :min="1" :max="255"></el-input-number>-->
  78. <!-- <el-button style="position: absolute; left: 11rem; top: 0rem; width: 5rem" size="mini" icon="el-icon-add-location" @click="presetPosition(129, presetPos)">设置</el-button>-->
  79. <!-- <el-button style="position: absolute; left: 27rem; top: 0rem; width: 5rem" size="mini" type="primary" icon="el-icon-place" @click="presetPosition(130, presetPos)">调用</el-button>-->
  80. <!-- <el-button style="position: absolute; left: 16rem; top: 0rem; width: 5rem" size="mini" icon="el-icon-delete-location" @click="presetPosition(131, presetPos)">删除</el-button>-->
  81. <!-- <el-tag style="position :absolute; left: 0rem; top: 2.5rem; width: 5rem; text-align: center" size="medium">巡航速度</el-tag>-->
  82. <!-- <el-input-number style="position: absolute; left: 5rem; top: 2.5rem; width: 6rem" size="mini" v-model="cruisingSpeed" controls-position="right" :precision="0" :min="1" :max="4095"></el-input-number>-->
  83. <!-- <el-button style="position: absolute; left: 11rem; top: 2.5rem; width: 5rem" size="mini" icon="el-icon-loading" @click="setSpeedOrTime(134, cruisingGroup, cruisingSpeed)">设置</el-button>-->
  84. <!-- <el-tag style="position :absolute; left: 16rem; top: 2.5rem; width: 5rem; text-align: center" size="medium">停留时间</el-tag>-->
  85. <!-- <el-input-number style="position: absolute; left: 21rem; top: 2.5rem; width: 6rem" size="mini" v-model="cruisingTime" controls-position="right" :precision="0" :min="1" :max="4095"></el-input-number>-->
  86. <!-- <el-button style="position: absolute; left: 27rem; top: 2.5rem; width: 5rem" size="mini" icon="el-icon-timer" @click="setSpeedOrTime(135, cruisingGroup, cruisingTime)">设置</el-button>-->
  87. <!-- <el-tag style="position :absolute; left: 0rem; top: 4.5rem; width: 5rem; text-align: center" size="medium">巡航组编号</el-tag>-->
  88. <!-- <el-input-number style="position: absolute; left: 5rem; top: 4.5rem; width: 6rem" size="mini" v-model="cruisingGroup" controls-position="right" :precision="0" :min="0" :max="255"></el-input-number>-->
  89. <!-- <el-button style="position: absolute; left: 11rem; top: 4.5rem; width: 5rem" size="mini" icon="el-icon-add-location" @click="setCommand(132, cruisingGroup, presetPos)">添加点</el-button>-->
  90. <!-- <el-button style="position: absolute; left: 16rem; top: 4.5rem; width: 5rem" size="mini" icon="el-icon-delete-location" @click="setCommand(133, cruisingGroup, presetPos)">删除点</el-button>-->
  91. <!-- <el-button style="position: absolute; left: 21rem; top: 4.5rem; width: 5rem" size="mini" icon="el-icon-delete" @click="setCommand(133, cruisingGroup, 0)">删除组</el-button>-->
  92. <!-- <el-button style="position: absolute; left: 27rem; top: 5rem; width: 5rem" size="mini" type="primary" icon="el-icon-video-camera-solid" @click="setCommand(136, cruisingGroup, 0)">巡航</el-button>-->
  93. <!-- <el-tag style="position :absolute; left: 0rem; top: 7rem; width: 5rem; text-align: center" size="medium">扫描速度</el-tag>-->
  94. <!-- <el-input-number style="position: absolute; left: 5rem; top: 7rem; width: 6rem" size="mini" v-model="scanSpeed" controls-position="right" :precision="0" :min="1" :max="4095"></el-input-number>-->
  95. <!-- <el-button style="position: absolute; left: 11rem; top: 7rem; width: 5rem" size="mini" icon="el-icon-loading" @click="setSpeedOrTime(138, scanGroup, scanSpeed)">设置</el-button>-->
  96. <!-- <el-tag style="position :absolute; left: 0rem; top: 9rem; width: 5rem; text-align: center" size="medium">扫描组编号</el-tag>-->
  97. <!-- <el-input-number style="position: absolute; left: 5rem; top: 9rem; width: 6rem" size="mini" v-model="scanGroup" controls-position="right" :precision="0" :step="1" :min="0" :max="255"></el-input-number>-->
  98. <!-- <el-button style="position: absolute; left: 11rem; top: 9rem; width: 5rem" size="mini" icon="el-icon-d-arrow-left" @click="setCommand(137, scanGroup, 1)">左边界</el-button>-->
  99. <!-- <el-button style="position: absolute; left: 16rem; top: 9rem; width: 5rem" size="mini" icon="el-icon-d-arrow-right" @click="setCommand(137, scanGroup, 2)">右边界</el-button>-->
  100. <!-- <el-button style="position: absolute; left: 27rem; top: 7rem; width: 5rem" size="mini" type="primary" icon="el-icon-video-camera-solid" @click="setCommand(137, scanGroup, 0)">扫描</el-button>-->
  101. <!-- <el-button style="position: absolute; left: 27rem; top: 9rem; width: 5rem" size="mini" type="danger" icon="el-icon-switch-button" @click="ptzCamera('stop')">停止</el-button>-->
  102. <!-- </el-button-group>-->
  103. </div>
  104. </div>
  105. </template>
  106. <script>
  107. import handle from "@/until/handle";
  108. import Microphone from "@/components/common/microphone"
  109. let queryTimer = null;
  110. let isZoom = null;
  111. let sendStopTimer = null;
  112. let changToLongDownStateTimer = null;
  113. // 是否长按
  114. let isLongDown = null;
  115. // 长按与连续短按的时间
  116. let pressDuration = 1000;
  117. // 从第一次按下按钮到执行命令时的重复时间
  118. let clickDuration = 700;
  119. // 连点持续时间
  120. let conClickDuration = 350;
  121. // 计时器
  122. let clickTimer = null;
  123. let conClickTimer = null;
  124. let pressTimer = null;
  125. let sendEndTimer = null;
  126. export default {
  127. name: "ptzControl",
  128. components: {Microphone},
  129. props:{
  130. deviceId:{require:true},
  131. channelId:{require:true}
  132. },
  133. data(){
  134. return {
  135. enableDebug: true,
  136. isLoading: false,
  137. tabActiveName: 'control',
  138. controSpeed: 30,
  139. zoomSpeed: 30,
  140. presetPos: 1,
  141. cruisingSpeed: 100,
  142. cruisingTime: 5,
  143. cruisingGroup: 0,
  144. scanSpeed: 100,
  145. scanGroup: 0,
  146. direction: '',// 当前按下的按钮的方向
  147. step:0,//步长
  148. stepValue:5,//
  149. clickCount: 0,// 连续点击数量
  150. isClick: true,// 是否为点击
  151. isLongClick: false,// 是否为连续点击
  152. isPress: false,// 是否为长按
  153. isSendAutoMove: false,// 是否为长按命令倒计时中
  154. pushKey: "",
  155. httpsHook: "",
  156. httpHook: "",
  157. presetList: [],
  158. presetLoading: false,
  159. }
  160. },
  161. beforeMount() {
  162. // this.queryPushParam();
  163. },
  164. methods:{
  165. timeSendFocus(){
  166. queryTimer = setTimeout(async ()=>{
  167. await this.ptzCameraFocus();
  168. queryTimer = null;
  169. },700)
  170. },
  171. timeSendStop(){
  172. console.log('短按自动跟发stop');
  173. this.ptzCamera('stop');
  174. },
  175. async ptzCamera(command){
  176. console.log('云台控制:' + command);
  177. let isSendFocus = false;
  178. let that = this;
  179. let isAutoSendStop = false;
  180. if(command === 'zoomin' || command === 'zoomout'){
  181. isZoom = true;
  182. if (queryTimer!=null){
  183. // 中止
  184. clearTimeout(queryTimer);
  185. }
  186. }else if(command === 'stop' && isZoom){
  187. // 发送待定值
  188. isSendFocus = true;
  189. }else{
  190. isZoom = false;
  191. // down 发送特定指令值.
  192. }
  193. clearTimeout(sendStopTimer);
  194. sendStopTimer = null;
  195. // 不连续发送指令
  196. if(command !== 'stop'){
  197. isLongDown = false;
  198. // 非停止指令
  199. changToLongDownStateTimer = setTimeout(()=>{
  200. isLongDown = true;
  201. },1000)
  202. }else{
  203. // 确保不是自动对焦
  204. if(!isLongDown && !isSendFocus){
  205. // 短按阻止立即发送end,等待900ms发送end
  206. sendStopTimer = setTimeout(()=>{
  207. this.timeSendStop();
  208. },1200);
  209. console.log('进行短按操作');
  210. return;
  211. }
  212. // 清除定时器
  213. clearTimeout(changToLongDownStateTimer);
  214. changToLongDownStateTimer = null;
  215. }
  216. let [err,res] = await handle(this.$axios.axios({
  217. method: 'post',
  218. url: '/api/ptz/control/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&horizonSpeed=' + this.controSpeed + '&verticalSpeed=' + this.controSpeed + '&zoomSpeed=' + this.zoomSpeed
  219. }));
  220. if(err){
  221. console.error(err)}
  222. if(isSendFocus){
  223. // TODO 在变焦后自动跟发聚焦指令
  224. // this.timeSendFocus();
  225. }
  226. },
  227. async ptzCameraFocus(){
  228. // todo 发送聚焦http指令
  229. console.log("摄像头聚焦");
  230. let url = `/api/ptz/focus/`
  231. url+=`${this.deviceId}/`;
  232. url+=`${this.channelId}/`;
  233. let [err,res] = await handle(this.$axios.axios({
  234. method: 'post',
  235. url: url
  236. }));
  237. if(err){
  238. console.error(err)}
  239. },
  240. presetPosition: function (cmdCode, presetPos) {
  241. console.log('预置位控制:' + this.presetPos + ' : 0x' + cmdCode.toString(16));
  242. let that = this;
  243. this.$axios.axios({
  244. method: 'post',
  245. url: '/api/ptz/front_end_command/' + this.deviceId + '/' + this.channelId + '?cmdCode=' + cmdCode + '&parameter1=0&parameter2=' + presetPos + '&combindCode2=0'
  246. }).then(function (res) {});
  247. },
  248. setSpeedOrTime: function (cmdCode, groupNum, parameter) {
  249. let that = this;
  250. let parameter2 = parameter % 256;
  251. let combindCode2 = Math.floor(parameter / 256) * 16;
  252. console.log('前端控制:0x' + cmdCode.toString(16) + ' 0x' + groupNum.toString(16) + ' 0x' + parameter2.toString(16) + ' 0x' + combindCode2.toString(16));
  253. this.$axios.axios({
  254. method: 'post',
  255. url: '/api/ptz/front_end_command/' + this.deviceId + '/' + this.channelId + '?cmdCode=' + cmdCode + '&parameter1=' + groupNum + '&parameter2=' + parameter2 + '&combindCode2=' + combindCode2
  256. }).then(function (res) {});
  257. },
  258. setCommand: function (cmdCode, groupNum, parameter) {
  259. let that = this;
  260. console.log('前端控制:0x' + cmdCode.toString(16) + ' 0x' + groupNum.toString(16) + ' 0x' + parameter.toString(16) + ' 0x0');
  261. this.$axios.axios({
  262. method: 'post',
  263. url: '/api/ptz/front_end_command/' + this.deviceId + '/' + this.channelId + '?cmdCode=' + cmdCode + '&parameter1=' + groupNum + '&parameter2=' + parameter + '&combindCode2=0'
  264. }).then(function (res) {});
  265. },
  266. /**
  267. * 按下云台控制按钮逻辑
  268. * @param direction 方向
  269. */
  270. ptzControlHandleDown(direction){
  271. if(sendStopTimer){
  272. clearTimeout(sendStopTimer);
  273. }
  274. console.log('--------------按下')
  275. this.direction = direction;
  276. this.isPress = false;
  277. this.isClick = true;
  278. // 1200
  279. pressTimer = setTimeout(()=>{
  280. console.log('长按')
  281. // 长按
  282. this.isPress = true;
  283. this.isClick=false;
  284. this.clickCount = 0;
  285. this.isSendAutoMove = false;
  286. // 发送云台移动命令,步长为0,视作连续移动
  287. this.sendCommand(this.direction,0);
  288. // 等待850毫秒,如果850毫秒内的抬起了鼠标,则发送停止命令
  289. setTimeout(()=>{
  290. console.log(`按下的延迟isSendAutoMove: ${this.isSendAutoMove}`)
  291. if(this.isSendAutoMove){
  292. console.log('长按抬起延迟结束');
  293. this.sendCommand('stop',0);
  294. }
  295. this.isSendAutoMove = true;
  296. },600);
  297. },pressDuration);
  298. // 处于连点状态,刷新连点计时器
  299. clearTimeout(conClickTimer);
  300. conClickTimer = null;
  301. },
  302. /**
  303. * 松开按钮逻辑
  304. * @param command
  305. */
  306. ptzControlHandleUp(command){
  307. if(this.isPress){
  308. // 如果没有抬起
  309. console.log(111111111)
  310. let _isSendAutoMove = this.isSendAutoMove;
  311. if(!_isSendAutoMove){
  312. console.log('长按')
  313. this.isSendAutoMove = true;
  314. return;
  315. }
  316. console.log('长按抬起结束')
  317. this.sendCommand('stop',0)
  318. }else{
  319. clearTimeout(pressTimer);
  320. this.clickCount ++;
  321. conClickTimer = setTimeout(()=>{
  322. // 结束连点,合并命令.
  323. this.isClick = false;
  324. conClickTimer=null;
  325. clickTimer=null;
  326. // 发送
  327. console.log(`快速点按${this.clickCount}`)
  328. clearTimeout(clickTimer);
  329. this.sendCommand(this.direction,this.clickCount);
  330. },conClickDuration);
  331. if(!clickTimer){
  332. clickTimer = setTimeout(()=>{
  333. // 连点超时
  334. if(this.isClick){
  335. clearTimeout(conClickTimer);
  336. conClickTimer=null;
  337. clickTimer=null;
  338. // 强制发送当前的
  339. console.log(`连按缓存${this.clickCount}`);
  340. this.sendCommand(this.direction,this.clickCount);
  341. }
  342. },clickDuration)
  343. }
  344. }
  345. },
  346. /**
  347. * 发送命令至服务器
  348. * @param command
  349. * @param step
  350. * @returns {Promise<void>}
  351. */
  352. async sendCommand(command,step=0)
  353. {
  354. console.log(`[send] ${command} - ${step}`);
  355. // step = step * 5
  356. let url = `/api/ptz/c/${this.deviceId}/${this.channelId}/?c=${command}&step=${step*this.stepValue}`
  357. console.log(url);
  358. let [err,res] = await handle(this.$axios.axios({
  359. method: 'post',
  360. url: url
  361. }));
  362. this.clickCount = 0;
  363. if(err){console.error(err)}
  364. },
  365. async queryPushParam()
  366. {
  367. let url = `/api/server/pushConfig`
  368. let [err,res] = await handle(this.$axios.axios({
  369. method: 'get',
  370. url: url
  371. }));
  372. if(err){
  373. console.error(err)
  374. return this.$message.error(err.message);
  375. }
  376. console.log(res);
  377. let response = res.data;
  378. if(response.code === 0){
  379. this.httpsHook = response.data["httpsHook"];
  380. this.httpHook = response.data["httpHook"];
  381. this.pushKey = response.data["pushKey"];
  382. }else{
  383. this.$message.warning(res.msg)
  384. }
  385. },
  386. async queryPresetPos(){
  387. console.log('请求预置位');
  388. this.presetLoading = true;
  389. let n_presetLength = 255;
  390. let presetList = new Array(n_presetLength);
  391. let queryUrl = `/api/ptz/preset/query/${this.deviceId}/${this.channelId}`
  392. // 加载预置位
  393. let [err,res] = await handle(this.$axios.axios({
  394. method: 'get',
  395. url: queryUrl
  396. }));
  397. this.presetLoading = false;
  398. presetList = presetList.map((item,i)=>{
  399. return {
  400. ind: i+1,
  401. remark: `预置位${i+1}`,
  402. load: false,
  403. }
  404. })
  405. if (err){
  406. if(err){
  407. console.error(err)
  408. this.presetList = presetList;
  409. return this.$message.error(err.message);
  410. }
  411. }
  412. console.log(res);
  413. let response = res.data;
  414. if (response.code === 0){
  415. }else{
  416. this.$message.warning(res.msg)
  417. }
  418. }
  419. },
  420. }
  421. </script>
  422. <style scoped>
  423. .control-mic{
  424. width: 4rem;
  425. /*height: 100%;*/
  426. display: flex;
  427. justify-content: center;
  428. align-items: center;
  429. }
  430. .control-wrapper {
  431. position: relative;
  432. width: 6.25rem;
  433. height: 6.25rem;
  434. max-width: 6.25rem;
  435. max-height: 6.25rem;
  436. border-radius: 100%;
  437. margin-top: 1.5rem;
  438. margin-left: 0.5rem;
  439. float: left;
  440. }
  441. .control-panel {
  442. position: relative;
  443. top: 0;
  444. left: 5rem;
  445. height: 11rem;
  446. max-height: 11rem;
  447. }
  448. .control-btn {
  449. display: flex;
  450. justify-content: center;
  451. position: absolute;
  452. width: 44%;
  453. height: 44%;
  454. border-radius: 5px;
  455. border: 1px solid #78aee4;
  456. box-sizing: border-box;
  457. transition: all 0.3s linear;
  458. }
  459. .control-btn:hover {
  460. cursor:pointer
  461. }
  462. .control-btn i {
  463. font-size: 20px;
  464. color: #78aee4;
  465. display: flex;
  466. justify-content: center;
  467. align-items: center;
  468. }
  469. .control-btn i:hover {
  470. cursor:pointer
  471. }
  472. .control-zoom-btn:hover {
  473. cursor:pointer
  474. }
  475. .control-round {
  476. position: absolute;
  477. top: 21%;
  478. left: 21%;
  479. width: 58%;
  480. height: 58%;
  481. background: #fff;
  482. border-radius: 100%;
  483. }
  484. .control-round-inner {
  485. position: absolute;
  486. left: 13%;
  487. top: 13%;
  488. display: flex;
  489. justify-content: center;
  490. align-items: center;
  491. width: 70%;
  492. height: 70%;
  493. font-size: 40px;
  494. color: #78aee4;
  495. border: 1px solid #78aee4;
  496. border-radius: 100%;
  497. transition: all 0.3s linear;
  498. }
  499. .control-inner-btn {
  500. position: absolute;
  501. width: 60%;
  502. height: 60%;
  503. background: #fafafa;
  504. }
  505. .control-top {
  506. top: -8%;
  507. left: 27%;
  508. transform: rotate(-45deg);
  509. border-radius: 5px 100% 5px 0;
  510. }
  511. .control-top i {
  512. transform: rotate(45deg);
  513. border-radius: 5px 100% 5px 0;
  514. }
  515. .control-top .control-inner {
  516. left: -1px;
  517. bottom: 0;
  518. border-top: 1px solid #78aee4;
  519. border-right: 1px solid #78aee4;
  520. border-radius: 0 100% 0 0;
  521. }
  522. .control-top .fa {
  523. transform: rotate(45deg) translateY(-7px);
  524. }
  525. .control-left {
  526. top: 27%;
  527. left: -8%;
  528. transform: rotate(45deg);
  529. border-radius: 5px 0 5px 100%;
  530. }
  531. .control-left i {
  532. transform: rotate(-45deg);
  533. }
  534. .control-left .control-inner {
  535. right: -1px;
  536. top: -1px;
  537. border-bottom: 1px solid #78aee4;
  538. border-left: 1px solid #78aee4;
  539. border-radius: 0 0 0 100%;
  540. }
  541. .control-left .fa {
  542. transform: rotate(-45deg) translateX(-7px);
  543. }
  544. .control-right {
  545. top: 27%;
  546. right: -8%;
  547. transform: rotate(45deg);
  548. border-radius: 5px 100% 5px 0;
  549. }
  550. .control-right i {
  551. transform: rotate(-45deg);
  552. }
  553. .control-right .control-inner {
  554. left: -1px;
  555. bottom: -1px;
  556. border-top: 1px solid #78aee4;
  557. border-right: 1px solid #78aee4;
  558. border-radius: 0 100% 0 0;
  559. }
  560. .control-right .fa {
  561. transform: rotate(-45deg) translateX(7px);
  562. }
  563. .control-bottom {
  564. left: 27%;
  565. bottom: -8%;
  566. transform: rotate(45deg);
  567. border-radius: 0 5px 100% 5px;
  568. }
  569. .control-bottom i {
  570. transform: rotate(-45deg);
  571. }
  572. .control-bottom .control-inner {
  573. top: -1px;
  574. left: -1px;
  575. border-bottom: 1px solid #78aee4;
  576. border-right: 1px solid #78aee4;
  577. border-radius: 0 0 100% 0;
  578. }
  579. .control-bottom .fa {
  580. transform: rotate(-45deg) translateY(7px);
  581. }
  582. .trank {
  583. width: 80%;
  584. height: 180px;
  585. text-align: left;
  586. padding: 0 10%;
  587. overflow: auto;
  588. }
  589. .trankInfo {
  590. width: 80%;
  591. padding: 0 10%;
  592. }
  593. </style>