AlertModal.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <template>
  2. <!--<transition name="alert-fade">-->
  3. <div v-if="visible" class="alert-overlay" @click.self="close">
  4. <div class="alert-modal">
  5. <div class="alert-header">
  6. <span class="alert-icon">&#9888;</span>
  7. <span class="alert-title">安 全 预 警</span>
  8. </div>
  9. <div class="alert-body">
  10. <div class="alert-left">
  11. <div class="alert-info-row">
  12. <span class="air-label">实 验 室:</span>
  13. <span class="air-value bold">{{ info.lab || '-' }}</span>
  14. </div>
  15. <div class="alert-info-row">
  16. <span class="air-label">楼栋楼层:</span>
  17. <span class="air-value bold">{{ info.building || '-' }}</span>
  18. </div>
  19. <div class="alert-info-row">
  20. <span class="air-label">所属单位:</span>
  21. <span class="air-value bold">{{ info.unit || '-' }}</span>
  22. </div>
  23. <div class="alert-info-row">
  24. <span class="air-label">异常参数:</span>
  25. <span class="air-value warn">{{ info.param || '-' }}</span>
  26. </div>
  27. <div class="alert-info-row">
  28. <span class="air-label">当前数值:</span>
  29. <span class="air-value bold">{{ info.value || '-' }}</span>
  30. </div>
  31. <div class="alert-info-row">
  32. <span class="air-label">实验室负责人:</span>
  33. <span class="air-value bold">{{ info.person || '-' }}</span>
  34. </div>
  35. <div class="alert-info-row">
  36. <span class="air-label">联系电话:</span>
  37. <span class="air-value bold">{{ info.phone || '-' }}</span>
  38. </div>
  39. <div class="alert-info-row">
  40. <span class="air-label">预警时间:</span>
  41. <span class="air-value warn">{{ info.time || '-' }}</span>
  42. </div>
  43. </div>
  44. <div class="alert-right">
  45. <div class="video-label">
  46. <span class="video-dot"></span>
  47. <span>实时监控画面</span>
  48. </div>
  49. <div class="video-area">
  50. <div class="video-header">
  51. <span class="rec-indicator"><span class="rec-dot"></span> REC</span>
  52. <span class="rec-name">{{ info.lab || '' }}</span>
  53. </div>
  54. <div class="video-placeholder" v-if="!videoData">
  55. <i class="el-icon-video-camera"></i>
  56. <span>实时监控画面</span>
  57. </div>
  58. <H5PlayerVideo style="margin:10px 0 0 12px;" v-if="videoData" :videoProps="videoData"></H5PlayerVideo>
  59. </div>
  60. </div>
  61. </div>
  62. <div class="alert-footer">
  63. <button class="btn-later" @click="$emit('close')">稍后处理</button>
  64. <button class="btn-emergency" @click="emergency()">应急疏散</button>
  65. <button class="btn-confirm" @click="shadeButton(7)">确认处理</button>
  66. </div>
  67. </div>
  68. <!--确认弹层-->
  69. <div class="shade-max-big-box" v-if="shadeType != 0">
  70. <div class="shade-big-box">
  71. <p class="off-button el-icon-close" @click="shadeButton(4)"></p>
  72. <div class="text-box" v-if="shadeType == 2 || shadeType == 3 || shadeType == 4 || shadeType == 5 || shadeType == 6">
  73. <p>{{shadeText}}</p>
  74. <p>{{shadeType==5?'关闭报警后,3分钟内系统不再触发预案报警,请核实确认后再执行此操作.':''}}</p>
  75. </div>
  76. <div class="button-box">
  77. <p class="button-null"></p>
  78. <p class="button-p" style="margin-right:39px;" @click="shadeButton(4)">取消</p>
  79. <p class="button-p" @click="shadeButton(5)">确认</p>
  80. <p class="button-null"></p>
  81. </div>
  82. </div>
  83. </div>
  84. <fullH5PlayerVideo v-if="fullVideoType" :fullVideoProps="fullVideoProps"></fullH5PlayerVideo>
  85. </div>
  86. <!--</transition>-->
  87. </template>
  88. <script>
  89. import H5PlayerVideo from '@/components/H5PlayerVideo/H5PlayerVideo.vue'
  90. import fullH5PlayerVideo from '@/components/fullH5PlayerVideo/fullH5PlayerVideo.vue'
  91. import { getVideoList,laboratoryPlanCloseRiskPlan } from '@/api'
  92. export default {
  93. name: 'AlertModal',
  94. components: { H5PlayerVideo,fullH5PlayerVideo },
  95. props: {
  96. AlertModalData: {
  97. type: Object,
  98. default: () => ({})
  99. }
  100. },
  101. data() {
  102. return {
  103. visible: false,
  104. info: {},
  105. //全屏视频参数
  106. videoData:null,
  107. fullVideoProps:{},
  108. fullVideoType:false,
  109. //弹窗相关
  110. shadeType:0,
  111. shadeText:'',
  112. shadeData:{},
  113. //结束预案时使用的预案ID
  114. checkRiskPlanId:null,
  115. }
  116. },
  117. mounted(){
  118. this.show(this.AlertModalData);
  119. },
  120. methods: {
  121. emergency(){
  122. // console.log('疏散切换');
  123. this.$parent.emergencyButton(2);
  124. },
  125. //遮罩层开关/弹层提示确认
  126. shadeButton(type){
  127. if(type == 4){
  128. this.$set(this,'shadeType',0)
  129. }else if(type == 5){
  130. if(this.shadeType == 5){
  131. //结束预案
  132. laboratoryPlanCloseRiskPlan({eventId:this.checkRiskPlanId}).then(response => {
  133. this.$emit('close')
  134. });
  135. }
  136. }else if(type == 7){
  137. // console.log('this.AlertModalData',this.AlertModalData)
  138. this.$set(this,'shadeText','传感器数据监测异常,确定要强制结束预案?');
  139. this.$set(this,'checkRiskPlanId',this.AlertModalData.eventId);
  140. this.$set(this,'shadeType',5);
  141. }
  142. },
  143. show(data) {
  144. const d = data || {}
  145. if (!d.time) {
  146. const now = new Date()
  147. const pad = n => String(n).padStart(2, '0')
  148. d.time = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`
  149. }
  150. this.info = d
  151. this.visible = true
  152. this.getVideoList(d);
  153. },
  154. close() {
  155. this.visible = false
  156. this.$emit('close')
  157. },
  158. async getVideoList(data) {
  159. try {
  160. let obj = {
  161. "subIds": [data.subId],
  162. "streamType": 1,
  163. "protocol": window.location.href.indexOf('https') !== -1 ? 'wss' : 'ws',
  164. "source": 4,
  165. "page": 1,
  166. "pageSize": 10
  167. }
  168. const res = await getVideoList(obj)
  169. if(res.data.list[0]){
  170. this.$set(this,'videoData',{
  171. width: 400, //(宽度:非必传-默认600)
  172. height: 210, //(高度:非必传-默认338)
  173. url: res.data.list[0].streamUrl,
  174. cameraIndexCode: res.data.list[0].deviceNo,
  175. });
  176. }
  177. } catch (e) {
  178. console.error('AlertModal:', e)
  179. }
  180. },
  181. //全屏开启
  182. stopTime(cameraIndexCode){
  183. this.$set(this,'fullVideoProps',{cameraIndexCode:cameraIndexCode});
  184. this.$set(this,'fullVideoType',true);
  185. },
  186. //全屏关闭
  187. outFullScreen(){
  188. this.$set(this,'fullVideoType',false);
  189. this.$set(this,'fullVideoProps',{});
  190. },
  191. }
  192. }
  193. </script>
  194. <style lang="scss" scoped>
  195. .shade-max-big-box{
  196. height:100%;
  197. width:100%;
  198. position: absolute;
  199. top:0;
  200. left:0;
  201. background: rgba(0,0,0,0.5);
  202. .shade-big-box{
  203. position: absolute;
  204. top:50%;
  205. left:50%;
  206. margin-left:-315px;
  207. margin-top:-125px;
  208. width:630px;
  209. height:250px;
  210. background: #011020;
  211. border:1px solid #116e8e;
  212. border-radius:10px;
  213. .off-button{
  214. position: absolute;
  215. right:15px;
  216. top:15px;
  217. color:#fff;
  218. font-size:20px;
  219. cursor: pointer;
  220. }
  221. .text-box{
  222. height:160px;
  223. color:#fff;
  224. overflow: hidden;
  225. p{
  226. padding:0 45px;
  227. font-size:20px;
  228. height:30px;
  229. line-height:30px;
  230. font-weight:500;
  231. }
  232. p:nth-child(1){
  233. margin-top:30px;
  234. }
  235. p:nth-child(2){
  236. margin-top:20px;
  237. }
  238. }
  239. .button-box{
  240. height:88px;
  241. border-top:2px solid #116e8e;
  242. display: flex;
  243. .button-null{
  244. flex:1;
  245. }
  246. .button-p{
  247. width:80px;
  248. height:40px;
  249. line-height:38px;
  250. margin-top:20px;
  251. text-align: center;
  252. border:1px solid #24D1F9;
  253. color:#fff;
  254. font-size:20px;
  255. border-radius:4px;
  256. cursor: pointer;
  257. }
  258. .button-p:hover{
  259. border:1px solid #24D1F9;
  260. background: #24D1F9;
  261. color:#fff;
  262. }
  263. }
  264. }
  265. }
  266. .alert-fade-enter-active, .alert-fade-leave-active {
  267. transition: opacity 0.35s ease;
  268. }
  269. .alert-fade-enter, .alert-fade-leave-to {
  270. opacity: 0;
  271. }
  272. .alert-overlay {
  273. position: fixed;
  274. inset: 0;
  275. z-index: 9999;
  276. display: flex;
  277. align-items: center;
  278. justify-content: center;
  279. background: rgba(10, 0, 0, 0.6);
  280. animation: alertOverlayGlow 2s ease-in-out infinite;
  281. }
  282. @keyframes alertOverlayGlow {
  283. 0%, 100% { box-shadow: inset 0 0 80px rgba(255, 40, 40, 0.06); }
  284. 50% { box-shadow: inset 0 0 140px rgba(255, 40, 40, 0.15); }
  285. }
  286. .alert-modal {
  287. width: 900px;
  288. background: rgba(18, 6, 10, 0.97);
  289. border: 1px solid rgba(255, 50, 50, 0.4);
  290. border-radius: 4px;
  291. overflow: hidden;
  292. box-shadow: 0 0 50px rgba(255, 0, 0, 0.12), 0 0 100px rgba(255, 0, 0, 0.05);
  293. }
  294. /* ---- Header ---- */
  295. .alert-header {
  296. display: flex;
  297. align-items: center;
  298. gap: 12px;
  299. padding: 14px 24px;
  300. background: linear-gradient(135deg, #c41818, #a01414);
  301. }
  302. .alert-icon {
  303. font-size: 22px;
  304. color: #fff;
  305. }
  306. .alert-title {
  307. font-size: 18px;
  308. font-weight: 700;
  309. color: #fff;
  310. letter-spacing: 6px;
  311. }
  312. /* ---- Body ---- */
  313. .alert-body {
  314. display: flex;
  315. padding: 24px 28px;
  316. gap: 28px;
  317. }
  318. .alert-left {
  319. flex: 1;
  320. min-width: 0;
  321. }
  322. .alert-right {
  323. width: 400px;
  324. flex-shrink: 0;
  325. }
  326. /* ---- Info Rows ---- */
  327. .alert-info-row {
  328. display: flex;
  329. align-items: baseline;
  330. padding: 8px 0;
  331. }
  332. .air-label {
  333. width: 112px;
  334. font-size: 14px;
  335. color: rgba(255, 90, 90, 0.7);
  336. flex-shrink: 0;
  337. }
  338. .air-value {
  339. font-size: 14px;
  340. color: rgba(255, 255, 255, 0.9);
  341. &.bold {
  342. font-weight: 600;
  343. }
  344. &.warn {
  345. color: #ff3333;
  346. font-weight: 600;
  347. }
  348. }
  349. /* ---- Video Section ---- */
  350. .video-label {
  351. display: flex;
  352. align-items: center;
  353. gap: 6px;
  354. font-size: 13px;
  355. color: rgba(255, 255, 255, 0.65);
  356. margin-bottom: 10px;
  357. }
  358. .video-dot {
  359. width: 8px;
  360. height: 8px;
  361. border-radius: 50%;
  362. background: #ff8c00;
  363. box-shadow: 0 0 6px rgba(255, 140, 0, 0.5);
  364. }
  365. .video-area {
  366. border: 1px solid rgba(255, 50, 50, 0.35);
  367. border-radius: 4px;
  368. overflow: hidden;
  369. background: rgba(0, 0, 0, 0.3);
  370. position: relative;
  371. }
  372. .video-header {
  373. position: absolute;
  374. display: flex;
  375. align-items: center;
  376. gap: 8px;
  377. padding: 8px 12px;
  378. font-size: 12px;
  379. color: rgba(255, 255, 255, 0.55);
  380. }
  381. .rec-indicator {
  382. display: flex;
  383. align-items: center;
  384. gap: 4px;
  385. color: rgba(255, 255, 255, 0.55);
  386. }
  387. .rec-dot {
  388. display: inline-block;
  389. width: 6px;
  390. height: 6px;
  391. border-radius: 50%;
  392. background: #ff4d4f;
  393. animation: recBlink 1.2s ease-in-out infinite;
  394. }
  395. @keyframes recBlink {
  396. 0%, 100% { opacity: 1; }
  397. 50% { opacity: 0.2; }
  398. }
  399. .rec-name {
  400. color: rgba(255, 255, 255, 0.55);
  401. }
  402. .video-placeholder {
  403. height: 180px;
  404. display: flex;
  405. flex-direction: column;
  406. align-items: center;
  407. justify-content: center;
  408. gap: 8px;
  409. color: rgba(255, 255, 255, 0.12);
  410. i { font-size: 40px; }
  411. span { font-size: 12px; }
  412. }
  413. /* ---- Footer ---- */
  414. .alert-footer {
  415. padding: 16px 28px 22px;
  416. display: flex;
  417. justify-content: center;
  418. }
  419. .btn-later {
  420. padding: 10px 52px;
  421. background-color: rgba(69, 90, 116, 0.2);
  422. color: rgba(69, 90, 116, 1);
  423. border: 2px solid rgba(69, 90, 116, 1);
  424. border-radius: 4px;
  425. font-size: 15px;
  426. letter-spacing: 8px;
  427. cursor: pointer;
  428. transition: all 0.3s ease;
  429. &:hover {
  430. background: rgba(69, 90, 116, 0.25);
  431. box-shadow: 0 0 20px rgba(69, 90, 116, 0.2);
  432. }
  433. }
  434. .btn-emergency {
  435. margin:0 40px;
  436. padding: 10px 52px;
  437. border-radius: 4px;
  438. background-color: rgba(245, 158, 11, 0.2);
  439. color: rgba(245, 158, 11, 1);
  440. border: 2px solid rgba(245, 158, 11, 1);
  441. font-size: 15px;
  442. letter-spacing: 8px;
  443. cursor: pointer;
  444. transition: all 0.3s ease;
  445. &:hover {
  446. background: rgba(245, 158, 11, 0.25);
  447. box-shadow: 0 0 20px rgba(245, 158, 11, 0.2);
  448. }
  449. }
  450. .btn-confirm {
  451. padding: 10px 52px;
  452. border-radius: 4px;
  453. background-color: rgba(239, 68, 68, 0.2);
  454. color: rgba(239, 68, 68, 1);
  455. border: 2px solid rgba(239, 68, 68, 1);
  456. font-size: 15px;
  457. letter-spacing: 8px;
  458. cursor: pointer;
  459. transition: all 0.3s ease;
  460. &:hover {
  461. background: rgba(239, 68, 68, 0.25);
  462. box-shadow: 0 0 20px rgba(239, 68, 68, 0.2);
  463. }
  464. }
  465. </style>