BoatKkjk.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <template>
  2. <div class="boat-info" :class="{'tab-bgxx': currentTab==='bgxx', 'tab-gzxx': currentTab==='gzxx'}">
  3. <div class="bi-header">
  4. <span class="bih-title">{{ props.boatInfo.shipNameCn || '未查到信息' }}</span>
  5. <div class="bih-btns">
  6. <span :class="{'highlight': cameraType==='down'}" @click="toggleCamera('down')">船身</span>
  7. <span :class="{'highlight': cameraType==='in'}" @click="toggleCamera('in')">船舱</span>
  8. <span :class="{'highlight': cameraType==='follow'}" @click="toggleCamera('follow')">船尾</span>
  9. </div>
  10. </div>
  11. <div class="dialog-tab bi-tab bottom-divider">
  12. <div :class="{'highlight': currentTab==='cbxx'}" @click="changeTab('cbxx')"><span>船舶信息</span></div>
  13. <div :class="{'highlight': currentTab==='gzxx'}" @click="changeTab('gzxx')"><span>感知信息</span></div>
  14. <div :class="{'highlight': currentTab==='bgxx'}" @click="changeTab('bgxx')"><span>报告信息</span></div>
  15. </div>
  16. <ul class="boat-fields cf-cbxx bottom-divider" v-if="currentTab==='cbxx'">
  17. <li><span>MMSI:</span><span>{{ props.boatInfo.mmsi }}</span></li>
  18. <li><span>船舶类型:</span><span>{{ props.boatInfo.shipTypeName || '-' }}</span></li>
  19. <li><span>船舶宽度:</span><span>{{ props.boatInfo.shipBreadth || '- ' }}米</span></li>
  20. <li><span>船舶长度:</span><span>{{ props.boatInfo.shipLength || '- ' }}米</span></li>
  21. <li><span>船舶总吨:</span><span>{{ props.boatInfo.shipGrossTon || '-' }}</span></li>
  22. <li><span>满载吃水:</span><span>{{ props.boatInfo.loadedDraft || '-' }}</span></li>
  23. <li style="margin-bottom: 0;"><span>空载吃水:</span><span>{{ props.boatInfo.noLoadedDraft || '-' }}</span></li>
  24. </ul>
  25. <ul class="boat-fields cf-bgxx bottom-divider" v-if="currentTab==='bgxx'">
  26. <li><span>停靠泊位:</span><span>--</span></li>
  27. <li><span>报告时间:</span><span>--</span></li>
  28. <li><span>预抵时间:</span><span>--</span></li>
  29. <li><span>当前港口:</span><span>--</span></li>
  30. <li><span>上一港口:</span><span>--</span></li>
  31. <li><span>下一港口:</span><span>--</span></li>
  32. <li><span>申报人员:</span><span>--</span></li>
  33. <li><span>申报电话:</span><span>--</span></li>
  34. </ul>
  35. <div class="content-gzxx bottom-divider" v-if="currentTab==='gzxx'">
  36. <div class="sjrh-wrapper bottom-divider">
  37. <span>数据融合:</span>
  38. <span class="sjrh-btn" :class="{'disabled': !sjrhData.video}">视频</span>
  39. <span class="sjrh-btn" :class="{'disabled': !sjrhData.laser}">激光</span>
  40. <span class="sjrh-btn" :class="{'disabled': !sjrhData.AIS}">AIS</span>
  41. <span class="sjrh-btn" :class="{'disabled': !sjrhData.RFID}">RFID</span>
  42. </div>
  43. <ul class="gzxx-fields boat-fields">
  44. <li><span>航向:</span><span>{{ props.boatInfo.inOrOut || '-' }}</span></li>
  45. <li><span>航速:</span><span>{{ props.boatInfo.speed || '- ' }}(公里/时)</span></li>
  46. <li><span>载重:</span><span>{{ props.boatInfo.load || '-' }}</span></li>
  47. <li><span>船长:</span><span>{{ props.boatInfo.length || '-' }}</span></li>
  48. <li><span>船宽:</span><span>{{ props.boatInfo.width || '-' }}</span></li>
  49. <li><span>船高:</span><span>{{ props.boatInfo.height || '-' }}</span></li>
  50. </ul>
  51. <ul class="gzxx-warning">
  52. <li v-for="item in warningData.value" :class="{'isOn': item.isWarning}"><i></i><span>{{ item.name }}</span></li>
  53. </ul>
  54. </div>
  55. <div class="boat-playback">
  56. <div class="cb-row1">
  57. <span :class="{'highlight': bottomType==='playback'}" @click="toggleBottom('playback')">轨迹回放</span>
  58. <span :class="{'highlight': bottomType==='pic'}" @click="toggleBottom('pic')">过船图片</span>
  59. </div>
  60. <div class="cb-time">
  61. <div>
  62. <i class="cbt-icon"></i>
  63. <el-date-picker
  64. v-model="timeRange.time1"
  65. type="datetime"
  66. placeholder="请选择"
  67. size="small"
  68. popper-class="date-popper"
  69. class="date-picker-custom1"
  70. value-format="YYYY-MM-DD HH:mm:ss"
  71. />
  72. </div>
  73. <div>
  74. <i class="cbt-icon"></i>
  75. <el-date-picker
  76. v-model="timeRange.time2"
  77. type="datetime"
  78. placeholder="请选择"
  79. size="small"
  80. popper-class="date-popper"
  81. class="date-picker-custom1"
  82. value-format="YYYY-MM-DD HH:mm:ss"
  83. />
  84. </div>
  85. </div>
  86. <div class="cb-play">
  87. <span class="speed" :class="{'selected': playSpeed===1.5}" @click="ChangePlaySpeed(1.5)">x1.5</span>
  88. <span class="speed" :class="{'selected': playSpeed===2}" @click="ChangePlaySpeed(2)">x2.0</span>
  89. <span class="speed" :class="{'selected': playSpeed===3}" @click="ChangePlaySpeed(3)">x3.0</span>
  90. <span class="play-btn" :class="{'btn-disabled': playState===-1}" v-show="playState<1" @click="track_play">播放</span>
  91. <span class="play-btn" v-show="playState===1||playState===2" @click="track_stop">停止</span>
  92. <span class="play-btn" v-show="playState===1" @click="track_pause">暂停</span>
  93. <span class="play-btn" v-show="playState===2" @click="track_resume">继续</span>
  94. </div>
  95. </div>
  96. <div class="pic-carousel-wrapper" v-show="picsShow">
  97. <i class="pc-switch-left" @click="pcSwitch('left')"></i>
  98. <i class="pc-switch-right" @click="pcSwitch('right')"></i>
  99. <i class="pc-close" @click="picsShow=false;bottomType='playback'"></i>
  100. <el-carousel
  101. type="card"
  102. class="pic-carousel"
  103. arrow="never"
  104. :autoplay="false"
  105. ref="pic_carousel"
  106. >
  107. <el-carousel-item v-for="pic, index in props.boatInfo.photoList" :key="pic">
  108. <img :src="pic" :alt="'过船图片-'+(index+1)" class="pics">
  109. </el-carousel-item>
  110. </el-carousel>
  111. </div>
  112. </div>
  113. </template>
  114. <script>
  115. export default {
  116. name: 'BoatKkjk',
  117. }
  118. </script>
  119. <script setup>
  120. import { reactive, ref, watch, onBeforeUnmount, nextTick } from 'vue'
  121. import { ElDatePicker } from 'element-plus'
  122. import 'element-plus/es/components/date-picker/style/css'
  123. import { ElCarousel, ElCarouselItem } from 'element-plus'
  124. import 'element-plus/es/components/carousel/style/css'
  125. import 'element-plus/es/components/carousel-item/style/css'
  126. import bus from '@/utils/bus'
  127. import { ueCallBoatGuiji, ueCallSetBoatDriveSpeed, ueCallBoatDrive, ueCallBoatCloseDrive, ueCallBoatStop, ueCallBoatContinue, ueCallChangeTrackType } from '@/utils/UIInteractions'
  128. import { useDateFormat } from '@vueuse/core'
  129. const props = defineProps(['boat-info'])
  130. const cameraType = ref('follow')
  131. function toggleCamera(type) {
  132. cameraType.value = type
  133. ueCallChangeTrackType(type)
  134. }
  135. const sjrhData = reactive({
  136. video: false,
  137. laser: false,
  138. AIS: false,
  139. RFID: false,
  140. })
  141. watch(()=>props.boatInfo, (val) => {
  142. nextTick(() => {
  143. warningData.value.forEach(i => {
  144. if(val.warningList.length===0) {
  145. i.isWarning = false
  146. } else {
  147. val.warningList.forEach(j => {
  148. if(i.fullName===j.warningType) {
  149. i.isWarning = true
  150. return
  151. } else {
  152. i.isWarning = false
  153. }
  154. })
  155. }
  156. })
  157. if(!val.isFinish) { return }
  158. val.isFinish.split('').forEach((i,index) => {
  159. switch (index) {
  160. case 0:
  161. sjrhData.AIS = +i
  162. break
  163. case 1:
  164. sjrhData.video = +i
  165. break
  166. case 3:
  167. sjrhData.RFID = +i
  168. }
  169. })
  170. timeRange.time1 = useDateFormat((new Date).getTime() - 30 * 60 * 1000, 'YYYY-MM-DD HH:mm:00').value
  171. timeRange.time2 = useDateFormat((new Date).getTime(), 'YYYY-MM-DD HH:mm:00').value
  172. })
  173. },{immediate:true})
  174. const currentTab = ref('cbxx')
  175. const warningData = reactive({value:[
  176. { name: 'AIS', fullName: 'AIS未开启', isWarning: false },
  177. { name: '报港', fullName: '申报预警', isWarning: false },
  178. { name: '超载', fullName: '超载预警', isWarning: false },
  179. { name: '重点', fullName: '重点监控船舶', isWarning: false },
  180. // { name: '超限', fullName: '超限预警', isWarning: false },
  181. { name: '证书', fullName: '船舶证书预警', isWarning: false },
  182. // { name: '救生衣', fullName: '未穿救生衣', isWarning: false },
  183. { name: '自定义', fullName: '自定义预警', isWarning: false },
  184. ]})
  185. const timeRange = reactive({
  186. time1: '',
  187. time2: ''
  188. })
  189. bus.on('ueRec_boatGuiji', (data) => {
  190. if(data.isOk=='true') {
  191. playState.value=0
  192. }
  193. })
  194. onBeforeUnmount(() => {
  195. bus.off('ueRec_boatGuiji')
  196. bus.off('ueRec_boatFockClear')
  197. ueCallBoatCloseDrive()
  198. })
  199. const bottomType = ref('playback')
  200. const picsShow = ref(false)
  201. const pic_carousel = ref(null)
  202. function pcSwitch(type) {
  203. if(type==='left') {
  204. pic_carousel.value.prev()
  205. } else if(type==='right') {
  206. pic_carousel.value.next()
  207. }
  208. }
  209. function toggleBottom(type) {
  210. if(type==='pic') {
  211. picsShow.value = true
  212. // let len = document.getElementsByClassName('pics').length
  213. // for(let i=0; i<len; i++) {
  214. // document.getElementsByClassName('pics')[i].addEventListener('wheel', (e) => {
  215. // console.log(e)
  216. // })
  217. // }
  218. }
  219. bottomType.value = type
  220. }
  221. const playSpeed = ref(1)
  222. const playState = ref(0) /* 0--未开始/已结束; 1--播放中; 2--已暂停; -1--禁用状态 */
  223. function ChangePlaySpeed(s) {
  224. playSpeed.value = s===playSpeed.value? 1: s
  225. ueCallSetBoatDriveSpeed(playSpeed.value)
  226. }
  227. function track_play() {
  228. if(timeRange.time1&&timeRange.time2) {
  229. playState.value=-1
  230. ueCallBoatGuiji(timeRange.time1, timeRange.time2)
  231. let timer = setInterval(() => {
  232. if(playState.value===-1) { return }
  233. ueCallBoatDrive()
  234. playState.value = 1
  235. clearInterval(timer)
  236. }, 300);
  237. }
  238. }
  239. function track_stop() {
  240. playState.value = 0
  241. ueCallBoatCloseDrive()
  242. }
  243. function track_pause() {
  244. playState.value = 2
  245. ueCallBoatStop()
  246. }
  247. function track_resume() {
  248. playState.value = 1
  249. ueCallBoatContinue()
  250. }
  251. const emit = defineEmits(['closeBoatInfo'])
  252. function changeTab(name) {
  253. currentTab.value = name
  254. }
  255. </script>
  256. <style lang="scss" scoped>
  257. .boat-info {
  258. box-sizing: border-box;
  259. width: 429px;
  260. height: 374px;
  261. background: url('@/assets/imgs/page_kkjk/bi-bg-1.png') no-repeat;
  262. background-size: contain;
  263. .dialog-close {
  264. top: 8px;
  265. }
  266. &.tab-bgxx {
  267. height: 408px;
  268. background: url('@/assets/imgs/page_kkjk/bi-bg-2.png') no-repeat;
  269. background-size: contain;
  270. }
  271. &.tab-gzxx {
  272. height: 494px;
  273. background: url('@/assets/imgs/page_kkjk/bi-bg-3.png') no-repeat;
  274. background-size: contain;
  275. }
  276. .bi-tab {
  277. padding-right: 20px;
  278. margin: 10px 0 20px;
  279. &>div.highlight::after {
  280. display: none;
  281. }
  282. }
  283. .cf-cbxx {
  284. margin: 15px 0 16px;
  285. li {
  286. margin-bottom: 10px;
  287. }
  288. }
  289. .cf-bgxx {
  290. margin-bottom: 22px;
  291. }
  292. .content-gzxx {
  293. margin-bottom: 28px;
  294. .sjrh-wrapper {
  295. display: flex;
  296. justify-content: space-between;
  297. align-items: center;
  298. box-sizing: border-box;
  299. padding: 0 40px 0 30px;
  300. margin-bottom: 25px;
  301. &>span:first-child {
  302. font-size: 14px;
  303. color: #D9E6FF;
  304. text-shadow: 0px 3px 5px rgba(0,38,76,0.4);
  305. }
  306. .sjrh-btn {
  307. display: block;
  308. width: 71px;
  309. height: 30px;
  310. background: url('@/assets/imgs/page_kkjk/bi-sjrh-btn1.png');
  311. background-size: 89px 37px;
  312. background-position: center;
  313. cursor: pointer;
  314. line-height: 30px;
  315. font-size: 14px;
  316. color: #eee;
  317. &.disabled {
  318. filter: brightness(0.5);
  319. }
  320. }
  321. }
  322. .gzxx-fields {
  323. &>li>span:first-child {
  324. width: 50px;
  325. }
  326. }
  327. .gzxx-warning {
  328. box-sizing: border-box;
  329. padding: 0 20px 0 10px;
  330. display: flex;
  331. justify-content: center;
  332. align-items: center;
  333. margin-top: 6px;
  334. &>li {
  335. display: flex;
  336. flex-direction: column;
  337. align-items: center;
  338. &.isOn {
  339. &>i {
  340. background: url('@/assets/imgs/page_kkjk/bi-warning-on.png');
  341. background-size: contain;
  342. }
  343. &>span {
  344. color: rgba($color: #fff, $alpha: 0.9);
  345. }
  346. }
  347. &>i {
  348. display: block;
  349. width: 20px;
  350. height: 20px;
  351. background: url('@/assets/imgs/page_kkjk/bi-warning-off.png');
  352. background-size: contain;
  353. margin-top: 8px;
  354. }
  355. &>span {
  356. font-size: 12px;
  357. line-height: 12px;
  358. color: rgba($color: #fff, $alpha: 0.3);
  359. }
  360. width: 51px;
  361. height: 51px;
  362. background: url('@/assets/imgs/page_kkjk/bi-warning-bg.png');
  363. background-size: contain;
  364. }
  365. }
  366. }
  367. .pic-carousel-wrapper {
  368. position: fixed;
  369. top: 0;
  370. left: 0;
  371. width: 100vw;
  372. height: 100vh;
  373. background-color: rgba($color: #000000, $alpha: 0.7);
  374. z-index: 999;
  375. :deep(.pic-carousel) {
  376. position: absolute;
  377. top: 20%;
  378. left: 50%;
  379. transform: translateX(-50%);
  380. width: 85%;
  381. height: 55vh;
  382. .el-carousel__indicators {
  383. display: none;
  384. }
  385. .el-carousel__container {
  386. height: 100%;
  387. }
  388. .el-carousel__item {
  389. box-sizing: border-box;
  390. border: 1px solid #4DA6FF;
  391. &:not(.is-active) {
  392. filter: brightness(60%);
  393. }
  394. &>img {
  395. width: 100%;
  396. height: 100%;
  397. }
  398. }
  399. }
  400. .pc-switch-right,.pc-switch-left {
  401. display: block;
  402. position: absolute;
  403. top: 46%;
  404. width: 35px;
  405. height: 59px;
  406. cursor: pointer;
  407. }
  408. .pc-switch-left {
  409. left: 4%;
  410. background: url('@/assets/imgs/navi/sxdx-arrow-left.png');
  411. background-size: contain;
  412. }
  413. .pc-switch-right {
  414. right: 4%;
  415. background: url('@/assets/imgs/navi/sxdx-arrow-right.png');
  416. background-size: contain;
  417. }
  418. .pc-close {
  419. display: block;
  420. position: absolute;
  421. bottom: 17%;
  422. left: calc(50% - 12px);
  423. width: 24px;
  424. height: 24px;
  425. cursor: pointer;
  426. background: url('@/assets/imgs/page_kkjk/bi-pics-close.png');
  427. background-size: contain;
  428. &:hover {
  429. transform: scale(1.1);
  430. }
  431. }
  432. }
  433. }
  434. </style>