index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. <template>
  2. <div class="inspection">
  3. <div class="left">
  4. <div class="tree">
  5. <monitorList
  6. @getClickId="getClickId"
  7. @getCameraList="getCameraList"
  8. ></monitorList>
  9. </div>
  10. </div>
  11. <div class="center">
  12. <div class="monitor">
  13. <myVideo
  14. :width="960"
  15. :height="540"
  16. show-reload-btn
  17. @setLoading="setLoading"
  18. ref="myVideoRef"
  19. />
  20. </div>
  21. </div>
  22. <div style="height: 100%; padding: 0">
  23. <div class="deviceInfo">
  24. <div class="frame-48095487">
  25. <div class="div">设备信息</div>
  26. </div>
  27. <div class="row">
  28. <div class="div">摄像机名称</div>
  29. <div class="name">{{ camera.name }}</div>
  30. </div>
  31. <div class="row">
  32. <div class="div">摄像机编号</div>
  33. <div class="div">{{ camera.deviceCode }}</div>
  34. </div>
  35. <div class="row">
  36. <div class="div">设备品牌</div>
  37. <div class="div">{{ camera.brandName }}</div>
  38. </div>
  39. <div class="row">
  40. <div class="div">设备型号</div>
  41. <div class="div">{{ camera.modelName }}</div>
  42. </div>
  43. </div>
  44. <div class="handle">
  45. <direction @handle="handle" />
  46. <div class="slider">
  47. <el-slider
  48. v-model="slider"
  49. :min="1"
  50. :max="7"
  51. style="width: 154px"
  52. ></el-slider>
  53. <div class="sliderNum">{{ slider }}</div>
  54. </div>
  55. <div class="moreHandle">
  56. <div class="row">
  57. <div class="item normal">
  58. <el-tooltip effect="dark" content="开关灯" placement="top">
  59. <img
  60. :src="
  61. require('@/assets/svgs/isp/ispRealTime/video/light.svg')
  62. "
  63. alt=""
  64. @click="switchLamp(camera.deviceCode)"
  65. />
  66. </el-tooltip>
  67. </div>
  68. <div class="item">
  69. <img
  70. :src="require('@/assets/svgs/isp/ispRealTime/video/yushua.svg')"
  71. alt=""
  72. />
  73. </div>
  74. <div class="item">
  75. <img
  76. :src="require('@/assets/svgs/isp/ispRealTime/video/jvjiao.svg')"
  77. alt=""
  78. />
  79. </div>
  80. <div class="item">
  81. <img
  82. :src="
  83. require('@/assets/svgs/isp/ispRealTime/video/chushihua.svg')
  84. "
  85. alt=""
  86. />
  87. </div>
  88. <div class="item">
  89. <img
  90. :src="require('@/assets/svgs/isp/ispRealTime/video/menu.svg')"
  91. alt=""
  92. />
  93. </div>
  94. </div>
  95. <div class="line"></div>
  96. <div class="row">
  97. <div class="item normal" v-loading="screenshotVal">
  98. <el-tooltip effect="dark" content="截图" placement="top">
  99. <img
  100. @click="screenshot(camera.deviceCode)"
  101. :src="require('@/assets/svgs/isp/ispRealTime/video/cw.svg')"
  102. alt=""
  103. />
  104. </el-tooltip>
  105. </div>
  106. <div class="item">
  107. <img
  108. :src="require('@/assets/svgs/isp/ispRealTime/video/3d.svg')"
  109. alt=""
  110. />
  111. </div>
  112. <div class="item"></div>
  113. <div class="item"></div>
  114. <div class="item"></div>
  115. </div>
  116. </div>
  117. <PresetPositions
  118. :PresetList="PresetList"
  119. :deviceCode="deviceCode"
  120. @getPreset="getPreset"
  121. ></PresetPositions>
  122. </div>
  123. </div>
  124. </div>
  125. </template>
  126. <script>
  127. import PresetPositions from './components/Preset-positions.vue';
  128. import monitorList from './components/monitorList.vue';
  129. import direction from './components/direction.vue';
  130. import myVideo from '../components/video.vue';
  131. import * as realTime from '@/api/isp/ispRealtime/monitor/index';
  132. import * as deviceApi from '@/api/isp/deviceManage/robot';
  133. // import FLVPlayer from "./FLVPlayer.vue";
  134. export default {
  135. name: 'MonitorPage',
  136. components: {
  137. PresetPositions,
  138. monitorList,
  139. direction,
  140. myVideo
  141. },
  142. data() {
  143. return {
  144. layout: 1,
  145. loading: false,
  146. videoList: [],
  147. carouselIndex: 0,
  148. isShow: false,
  149. deviceCode: undefined,
  150. camera: {},
  151. stopList: [],
  152. slider: 1,
  153. screenshotVal: false,
  154. PresetList: [],
  155. codeList: [],
  156. monitorData: []
  157. };
  158. },
  159. beforeDestroy() {
  160. if (this.deviceCode) {
  161. realTime.delStreamProxy(this.deviceCode);
  162. }
  163. },
  164. computed: {
  165. maxLayout() {
  166. if (this.videoList.length > 8) {
  167. return 4;
  168. } else if (this.videoList.length > 3) {
  169. return 3;
  170. } else if (this.videoList.length > 1) {
  171. return 2;
  172. } else {
  173. return 1;
  174. }
  175. },
  176. count() {
  177. return this.videoList.length;
  178. },
  179. pageNum() {
  180. let num = this.count / (this.layout * this.layout);
  181. return Math.ceil(num);
  182. },
  183. itemStyle() {
  184. return {
  185. width: `calc((100% - 10px * (${this.layout} - 1)) / ${this.layout})`,
  186. height: `calc((100% - 10px * (${this.layout} - 1)) / ${this.layout})`
  187. };
  188. }
  189. },
  190. watch: {
  191. deviceCode(val, oldVal) {
  192. if (oldVal) {
  193. realTime.delStreamProxy(oldVal);
  194. }
  195. this.getPreset();
  196. }
  197. },
  198. mounted() {},
  199. methods: {
  200. setLoading(loading) {
  201. this.loading = loading;
  202. },
  203. itemNum(pageIndex) {
  204. if (this.pageNum != 1 && pageIndex == this.pageNum - 1) {
  205. return this.count - this.layout * this.layout * (this.pageNum - 1);
  206. } else if (this.pageNum == 1) {
  207. return this.count;
  208. } else {
  209. return this.layout * this.layout;
  210. }
  211. },
  212. carouselChange(index) {
  213. this.carouselIndex = index;
  214. if (this.layout == 1) this.getClickId(this.monitorData[index]);
  215. },
  216. toggle(e) {
  217. this.isShow = !this.isShow;
  218. },
  219. getFocus() {
  220. const layout = document.getElementById('layout');
  221. if (layout) layout.focus();
  222. },
  223. blur() {
  224. this.isShow = false;
  225. },
  226. choose(index) {
  227. this.layout = index + 1;
  228. this.isShow = false;
  229. },
  230. home() {
  231. this.carouselIndex = 0;
  232. this.$refs.carouselRef && this.$refs.carouselRef.setActiveItem(0);
  233. },
  234. last() {
  235. if (this.carouselIndex > 0) {
  236. this.carouselIndex--;
  237. this.$refs.carouselRef &&
  238. this.$refs.carouselRef.setActiveItem(this.carouselIndex);
  239. } else {
  240. this.carouselIndex = this.pageNum - 1;
  241. this.$refs.carouselRef &&
  242. this.$refs.carouselRef.setActiveItem(this.pageNum - 1);
  243. }
  244. },
  245. next() {
  246. if (this.carouselIndex < this.pageNum - 1) {
  247. this.carouselIndex++;
  248. this.$refs.carouselRef &&
  249. this.$refs.carouselRef.setActiveItem(this.carouselIndex);
  250. } else {
  251. this.carouselIndex = 0;
  252. this.$refs.carouselRef && this.$refs.carouselRef.setActiveItem(0);
  253. }
  254. },
  255. end() {
  256. this.carouselIndex = this.pageNum - 1;
  257. this.$refs.carouselRef &&
  258. this.$refs.carouselRef.setActiveItem(this.pageNum - 1);
  259. },
  260. handleScreenshot(index, e) {
  261. const videoPlayback = document.getElementById('video' + index);
  262. if (!videoPlayback) return;
  263. const canvas = document.createElement('canvas');
  264. canvas.width = videoPlayback.videoWidth;
  265. canvas.height = videoPlayback.videoHeight;
  266. const ctx = canvas.getContext('2d');
  267. if (ctx) {
  268. ctx.drawImage(videoPlayback, 0, 0, canvas.width, canvas.height);
  269. }
  270. const img = new Image();
  271. img.src = canvas.toDataURL('image/png');
  272. const a = document.createElement('a');
  273. a.href = img.src;
  274. a.download = 'screenshot.png';
  275. document.body.appendChild(a);
  276. a.click();
  277. document.body.removeChild(a);
  278. e.stopPropagation();
  279. },
  280. async handle(SDK) {
  281. if (SDK == 'reset') {
  282. let params = {
  283. cameraCode: this.deviceCode,
  284. wPresetNum: 34,
  285. command: 'GOTO_PRESET'
  286. };
  287. const res = await realTime.oprPreset(params);
  288. if (res == 'SUCCESS') {
  289. this.$message.success('操作成功');
  290. } else {
  291. this.$message.error(res);
  292. }
  293. return;
  294. }
  295. let res = await realTime.playControl({
  296. cameraCode: this.deviceCode,
  297. mill: this.slider * 1000,
  298. command: SDK
  299. });
  300. if (res == 'SUCCESS') {
  301. this.$message.success('操作成功');
  302. } else {
  303. this.$message.error(res);
  304. }
  305. },
  306. async switchLamp(code) {
  307. if (!code) return this.$message.warning('当前设备异常');
  308. const data = await deviceApi.playControl({
  309. cameraCode: code,
  310. mill: 1000,
  311. command: 'LIGHT_PWRON'
  312. });
  313. if (data == 'SUCCESS') {
  314. this.$message.success('指令下发成功');
  315. } else {
  316. this.$message.error('指令下发失败');
  317. }
  318. },
  319. async screenshot(code) {
  320. if (!code) return this.$message.warning('当前设备异常');
  321. this.screenshotVal = true;
  322. try {
  323. const data = await deviceApi.catchPic(code);
  324. if (data.size < 100) {
  325. this.$message.warning('截图失败');
  326. } else {
  327. const dlink = document.createElement('a');
  328. dlink.download = '截图.png';
  329. dlink.style.display = 'none';
  330. dlink.href = URL.createObjectURL(data);
  331. document.body.appendChild(dlink);
  332. dlink.click();
  333. URL.revokeObjectURL(dlink.href);
  334. document.body.removeChild(dlink);
  335. this.$message.success('截图下载成功');
  336. }
  337. } finally {
  338. this.screenshotVal = false;
  339. }
  340. },
  341. playStop() {
  342. this.$refs.myVideoRef.playStop();
  343. // let index = Math.floor(
  344. // this.videoList.findIndex(
  345. // (item) => item.cameraCode == this.deviceCode
  346. // ) /
  347. // (this.layout * this.layout)
  348. // );
  349. // let videoElement = document.getElementById('video' + index);
  350. // if (videoElement && videoElement.paused) {
  351. // videoElement.play();
  352. // this.stopList = this.stopList.filter((item) => item != index);
  353. // } else {
  354. // if (videoElement) videoElement.pause();
  355. // this.stopList.push(index);
  356. // }
  357. },
  358. play(index) {
  359. this.$refs.myVideoRef.play();
  360. // let videoElement = document.getElementById('video' + index);
  361. // if (videoElement) videoElement.play();
  362. // this.stopList = this.stopList.filter((item) => item != index);
  363. },
  364. async getCameraList(list) {
  365. this.monitorData = list;
  366. list.forEach((item) => {
  367. this.codeList.push(item.deviceCode);
  368. });
  369. // this.getClickId(list[0]);
  370. },
  371. async getClickId(device) {
  372. this.camera = device;
  373. this.deviceCode = device.deviceCode;
  374. await this.getCameraUrl();
  375. let index = Math.floor(
  376. this.videoList.findIndex(
  377. (item) => item.cameraCode == device.deviceCode
  378. ) /
  379. (this.layout * this.layout)
  380. );
  381. this.$refs.carouselRef && this.$refs.carouselRef.setActiveItem(index);
  382. this.carouselIndex = index;
  383. },
  384. async getPreset() {
  385. const res = await realTime.getPreset(this.deviceCode);
  386. this.PresetList = res;
  387. },
  388. async getCameraUrl() {
  389. await realTime.delStreamProxy(this.deviceCode);
  390. const res = await realTime.getCameraUrl([this.deviceCode]);
  391. this.$refs.myVideoRef.startPlay(res[0].url);
  392. // this.videoList = res;
  393. console.log(this.videoList);
  394. }
  395. }
  396. };
  397. </script>
  398. <style lang="scss" scoped>
  399. .inspection {
  400. display: flex;
  401. width: 100%;
  402. .left {
  403. padding-right: 0;
  404. height: 100%;
  405. width: 232px;
  406. }
  407. .center {
  408. width: calc(100%);
  409. padding-left: 10px;
  410. padding-right: 10px;
  411. padding-bottom: 20px;
  412. }
  413. }
  414. .missonList,
  415. .missonList * {
  416. box-sizing: border-box;
  417. }
  418. .missonList {
  419. background: #fff;
  420. padding: 10px;
  421. display: flex;
  422. flex-direction: column;
  423. gap: 4px;
  424. align-items: flex-start;
  425. justify-content: flex-start;
  426. align-self: stretch;
  427. flex-shrink: 0;
  428. position: relative;
  429. width: 232px;
  430. .list {
  431. width: 100%;
  432. ::v-deep .el-scrollbar__thumb {
  433. display: none;
  434. }
  435. }
  436. .title {
  437. background: #f2f4f5;
  438. display: flex;
  439. flex-direction: row;
  440. gap: 1px;
  441. align-items: center;
  442. justify-content: center;
  443. align-self: stretch;
  444. flex-shrink: 0;
  445. height: 24px;
  446. position: relative;
  447. > div {
  448. color: #404446;
  449. text-align: left;
  450. font-family: 'Alibaba PuHuiTi 2.0', sans-serif;
  451. font-size: 14px;
  452. line-height: 16px;
  453. font-weight: 400;
  454. position: relative;
  455. }
  456. }
  457. .row {
  458. padding: 4px 0px 4px 0px;
  459. display: flex;
  460. flex-direction: row;
  461. align-items: center;
  462. justify-content: space-between;
  463. align-self: stretch;
  464. flex-shrink: 0;
  465. position: relative;
  466. &:hover {
  467. background: linear-gradient(
  468. 270deg,
  469. rgba(44, 138, 224, 0.44) 0%,
  470. rgba(44, 138, 224, 0.22) 119.59%
  471. );
  472. }
  473. }
  474. .name {
  475. color: rgb(64, 68, 70);
  476. text-align: left;
  477. font-family: var(
  478. --small-none-regular-font-family,
  479. 'Alibaba PuHuiTi 2.0',
  480. sans-serif
  481. );
  482. font-size: var(--small-none-regular-font-size, 14px);
  483. line-height: var(--small-none-regular-line-height, 16px);
  484. font-weight: var(--small-none-regular-font-weight, 400);
  485. position: relative;
  486. }
  487. .done {
  488. color: #32a2d4;
  489. text-align: left;
  490. font-family: var(
  491. --small-none-regular-font-family,
  492. 'Alibaba PuHuiTi 2.0',
  493. sans-serif
  494. );
  495. font-size: var(--small-none-regular-font-size, 14px);
  496. line-height: var(--small-none-regular-line-height, 16px);
  497. font-weight: var(--small-none-regular-font-weight, 400);
  498. position: relative;
  499. }
  500. .doing {
  501. color: #ffb323;
  502. text-align: left;
  503. font-family: var(
  504. --small-none-regular-font-family,
  505. 'Alibaba PuHuiTi 2.0',
  506. sans-serif
  507. );
  508. font-size: var(--small-none-regular-font-size, 14px);
  509. line-height: var(--small-none-regular-line-height, 16px);
  510. font-weight: var(--small-none-regular-font-weight, 400);
  511. position: relative;
  512. }
  513. .todo {
  514. color: #ff4d4f;
  515. text-align: left;
  516. font-family: var(
  517. --small-none-regular-font-family,
  518. 'Alibaba PuHuiTi 2.0',
  519. sans-serif
  520. );
  521. font-size: var(--small-none-regular-font-size, 14px);
  522. line-height: var(--small-none-regular-line-height, 16px);
  523. font-weight: var(--small-none-regular-font-weight, 400);
  524. position: relative;
  525. }
  526. }
  527. .tree {
  528. background-color: #fff;
  529. margin-top: 16px;
  530. }
  531. .el-carousel {
  532. ::v-deep .el-carousel__container {
  533. height: calc(100% - 27px);
  534. }
  535. }
  536. .deviceInfo,
  537. .deviceInfo * {
  538. box-sizing: border-box;
  539. }
  540. .deviceInfo {
  541. background: #fff;
  542. padding: 10px;
  543. display: flex;
  544. flex-direction: column;
  545. gap: 4px;
  546. align-items: flex-start;
  547. justify-content: flex-start;
  548. align-self: stretch;
  549. flex-shrink: 0;
  550. position: relative;
  551. width: 232px;
  552. .frame-48095487 {
  553. background: #f2f4f5;
  554. display: flex;
  555. flex-direction: row;
  556. gap: 1px;
  557. align-items: center;
  558. justify-content: center;
  559. align-self: stretch;
  560. flex-shrink: 0;
  561. height: 24px;
  562. position: relative;
  563. }
  564. .div {
  565. color: rgb(64, 68, 70);
  566. text-align: left;
  567. font-family: 'Alibaba PuHuiTi 2.0', sans-serif;
  568. font-size: 14px;
  569. line-height: 16px;
  570. font-weight: 400;
  571. position: relative;
  572. }
  573. .row {
  574. padding: 4px 0px 4px 0px;
  575. display: flex;
  576. flex-direction: row;
  577. align-items: center;
  578. justify-content: space-between;
  579. align-self: stretch;
  580. flex-shrink: 0;
  581. position: relative;
  582. }
  583. .name {
  584. color: #32a2d4;
  585. text-align: left;
  586. font-family: 'Alibaba PuHuiTi 2.0', sans-serif;
  587. font-size: 14px;
  588. line-height: 16px;
  589. font-weight: 400;
  590. position: relative;
  591. }
  592. }
  593. .handle {
  594. display: flex;
  595. padding: 10px;
  596. flex-direction: column;
  597. align-items: flex-start;
  598. gap: 16px;
  599. flex: 1 0 0;
  600. background: #fff;
  601. margin-top: 10px;
  602. }
  603. .slider {
  604. display: flex;
  605. justify-content: space-between;
  606. align-items: center;
  607. align-self: stretch;
  608. padding-left: 10px;
  609. .sliderNum {
  610. display: flex;
  611. height: 17px;
  612. padding: 10px;
  613. flex-direction: column;
  614. justify-content: center;
  615. align-items: center;
  616. gap: 10px;
  617. border: 1px solid #cdcfd0;
  618. width: 29px;
  619. box-sizing: border-box;
  620. ::v-deep .el-slider__button {
  621. background-color: #fff;
  622. border-color: #ff7b30;
  623. }
  624. }
  625. }
  626. .moreHandle {
  627. display: flex;
  628. width: 200px;
  629. padding: 5px 0px;
  630. flex-direction: column;
  631. justify-content: center;
  632. align-items: center;
  633. gap: 4px;
  634. position: relative;
  635. border-radius: 4px;
  636. border: 2px solid #e3e5e6;
  637. .row {
  638. display: flex;
  639. align-items: flex-start;
  640. align-self: stretch;
  641. }
  642. .line {
  643. width: 180px;
  644. height: 1px;
  645. background: #e3e5e6;
  646. position: absolute;
  647. top: 50%;
  648. left: 50%;
  649. transform: translate(-50%, -50%);
  650. }
  651. .item {
  652. display: flex;
  653. height: 21px;
  654. padding: 0px 9px;
  655. justify-content: center;
  656. align-items: center;
  657. width: 39px;
  658. cursor: not-allowed;
  659. border-left: 1px solid #e3e5e6;
  660. border-right: 1px solid #e3e5e6;
  661. &:first-child {
  662. border-left: 0;
  663. }
  664. &:last-child {
  665. border-right: 0;
  666. }
  667. }
  668. .normal {
  669. cursor: pointer;
  670. }
  671. }
  672. .center-handle {
  673. display: flex;
  674. height: 42px;
  675. justify-content: space-between;
  676. align-items: center;
  677. align-self: stretch;
  678. width: 100%;
  679. .layout-type {
  680. display: flex;
  681. width: 98px;
  682. align-items: center;
  683. position: relative;
  684. > div {
  685. display: flex;
  686. }
  687. }
  688. .play {
  689. display: flex;
  690. justify-content: center;
  691. width: 100%;
  692. align-items: flex-start;
  693. gap: 24px;
  694. }
  695. .video-handle {
  696. display: flex;
  697. align-items: flex-end;
  698. gap: 16px;
  699. }
  700. }
  701. .monitor {
  702. height: 100%;
  703. padding: 10px;
  704. }
  705. .layout {
  706. width: 20px;
  707. height: 15px;
  708. padding: 1px;
  709. display: flex;
  710. flex-wrap: wrap;
  711. gap: 1px;
  712. border: 1px #404446 solid;
  713. }
  714. .group {
  715. display: flex;
  716. padding: 4px;
  717. align-items: flex-start;
  718. gap: 4px;
  719. position: absolute;
  720. top: 20px;
  721. border-radius: 4px;
  722. border: 0.5px solid #404446;
  723. background: #fff;
  724. }
  725. </style>