emergencyEvacuationBig.vue 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210
  1. <!-- 应急疏散 -->
  2. <template>
  3. <view id="emergencyEvacuationBig">
  4. <view class="setUpEvacuation" v-if="pageType == 1">
  5. <view class="evacuation-max-box">
  6. <view class="picker-max-box">
  7. <view class="picker-title-box">
  8. <view></view>
  9. <view>楼栋</view>
  10. </view>
  11. <picker @change="buildingChange" :range-key="'name'" :range="buildingList">
  12. <view class="picker-min-box">
  13. <view>{{buildingName?buildingName:'请选择楼栋'}}</view>
  14. <img :src="imagesUrl('commonality/icon_06.png')">
  15. </view>
  16. </picker>
  17. </view>
  18. <view class="picker-max-box">
  19. <view class="picker-title-box">
  20. <view></view>
  21. <view>楼层</view>
  22. </view>
  23. <picker @change="floorChange" :disabled="!buildingId" :range-key="'name'" :range="floorList">
  24. <view class="picker-min-box">
  25. <view>{{floorName?floorName:'请选择楼层'}}</view>
  26. <img :src="imagesUrl('commonality/icon_06.png')">
  27. </view>
  28. </picker>
  29. </view>
  30. <view class="picker-max-box">
  31. <view class="picker-title-box">
  32. <view></view>
  33. <view>实验室</view>
  34. </view>
  35. <picker @change="fjListChange" :disabled="!floorId" :range-key="'subName'" :range="fjListArray">
  36. <view class="picker-min-box">
  37. <view>{{subName?subName:'请选择实验室'}}</view>
  38. <img :src="imagesUrl('commonality/icon_06.png')">
  39. </view>
  40. </picker>
  41. </view>
  42. </view>
  43. <view class="setUpEvacuation-bottom-button" @click="confirmBtn">确认</view>
  44. </view>
  45. <view class="implementEvacuation" v-if="pageType == 2">
  46. <view class="evacuation-max-box">
  47. <!-- 头部 -->
  48. <view class="evacuation-title-box">
  49. <view class="evacuation-title-left">
  50. <view class="evacuation-title-name-box">{{textFiltration(subName)}}{{roomNum?'('+textFiltration(roomNum)+')':''}}</view>
  51. <view class="site"><img :src="imagesUrl('commonality/icon_14.png')">{{textFiltration(buildingName)}}
  52. {{textFiltration(floorName)}}
  53. </view>
  54. </view>
  55. <view class="evacuation-title-right" @click="backButton()">选择房间</view>
  56. </view>
  57. <!-- 地图部分 -->
  58. <view class="roadmap">
  59. <view class="roadmap_t">
  60. <view class="monito_li_r_l"></view>
  61. <view class="monito_li_r_r_button" @click="goAllPage">全屏</view>
  62. </view>
  63. <view class="evacuation-map-box">
  64. <view class="emergencyEvacuationBigFullScreen-page" v-if="mapType"
  65. :style="'width:'+mapWidth+'rpx;height:'+mapHeight+'rpx;transform: scale('+zoomData+');margin-top:-'+mapHeight/2+'rpx;margin-left:-'+mapWidth/2+'rpx;'">
  66. <view class="map-max-box" :style="'width:'+mapWidth+'rpx;height:'+mapHeight+'rpx;'">
  67. <!-- 实验室 -->
  68. <view class="map-max-for-box for-map-box" v-if="item.type == 1" v-for="(item,index) in mapList"
  69. :key="index" :class="!item.policeType && subId ==item.subId ? 'room-type-one':(
  70. item.policeType && subId !=item.subId ? 'room-type-two':(
  71. item.policeType && subId ==item.subId ? 'room-type-three':(
  72. !item.loginAdmin ? 'room-type-noe':'')))"
  73. :style="'top:'+item.y+'rpx;left:'+item.x+'rpx;width:'+(item.w-4)+'rpx;height:'+(item.h-4)+'rpx;background:'+item.levelColor+';'">
  74. <view class="map-max-for-min-box">
  75. <view class="map-for-name-p" :style="'margin-top:'+((item.h/2)-20)+'rpx;'">
  76. {{item.roomType == '-99'?item.roomName:item.subName}}
  77. </view>
  78. <view class="map-for-num-p">({{item.roomNum}})</view>
  79. <view class="position-box" :src="imagesUrl('manage/icon_sysbjt_m.png')"
  80. :class="minItem.toward=='top'?'center-move-door-p-t':(minItem.toward=='bottom'?'center-move-door-p-b':(minItem.toward=='left'?'center-move-door-p-l':(minItem.toward=='right'?'center-move-door-p-r':'')))"
  81. v-for="(minItem,minIndex) in item.doorList" :key="minIndex"
  82. :style="'top:'+minItem.y+'rpx;left:'+minItem.x+'rpx;width:'+minItem.w+'rpx;height:'+minItem.h+'rpx;'">
  83. </view>
  84. </view>
  85. </view>
  86. <!-- 走廊 -->
  87. <view class="map-max-for-box for-map-box-one" v-if="item.type == 2" v-for="(item,index) in mapList"
  88. :key="index"
  89. :style="'top:'+item.y+'rpx;left:'+item.x+'rpx;width:'+item.w+'rpx;height:'+item.h+'rpx;'">
  90. <view class="map-max-for-min-box">
  91. <view class="position-box"
  92. :class="minItem.state=='1'&&minItem.openType?'lightTopOn':(minItem.state=='1'&&!minItem.openType?'lightTopOff':
  93. (minItem.state=='2'&&minItem.openType?'lightBottomOn':(minItem.state=='2'&&!minItem.openType?'lightBottomOff':
  94. (minItem.state=='3'&&minItem.openType?'lightLeftOn':(minItem.state=='3'&&!minItem.openType?'lightLeftOff':
  95. (minItem.state=='4'&&minItem.openType?'lightRightOn':(minItem.state=='4'&&!minItem.openType?'lightRightOff':'')))))))"
  96. v-for="(minItem,minIndex) in item.lightList" :key="minIndex"
  97. :style="'top:'+minItem.y+'rpx;left:'+minItem.x+'rpx;width:'+minItem.w+'rpx;height:'+minItem.h+'rpx;'">
  98. </view>
  99. </view>
  100. </view>
  101. <!-- 疏散口 -->
  102. <view class="map-max-for-box for-map-box-two" v-if="item.type == 3" v-for="(item,index) in mapList"
  103. :key="index" :class="item.roomCheckType?'for-map-box-two-check':''"
  104. :style="'top:'+item.y+'rpx;left:'+item.x+'rpx;width:'+item.w+'rpx;height:'+item.h+'rpx;'">
  105. </view>
  106. </view>
  107. </view>
  108. </view>
  109. </view>
  110. <!-- 视频部分 -->
  111. <!-- <view class="video-max-box">
  112. </view> -->
  113. <view class="device-type">
  114. <view @click="getVideo()">
  115. <img :src="imagesUrl('manage/icon_xq_spjk.png')">
  116. <view>视频监控</view>
  117. <img :src="imagesUrl('commonality/icon_wdwg_gd.png')">
  118. </view>
  119. </view>
  120. <view class="bottom-button-box">
  121. <view class="voice" @click="shadeTypeClick()">语音广播</view>
  122. <view class="plan" v-if="planStatus" @click="closePlan()">结束预案</view>
  123. <view class="evacuate" @click="evacuationButton(1)" v-if="isEvacuate">执行疏散</view>
  124. <view class="evacuate" @click="evacuationButton(2)" v-if="!isEvacuate">结束疏散</view>
  125. </view>
  126. </view>
  127. <!-- 语音广播-->
  128. <view class="shade-max-big-box" v-if="broadcastType">
  129. <view class="null-box" @click="shadeTypeClick()"></view>
  130. <!-- 语音广播-执行疏散 -->
  131. <view class="broadcast">
  132. <view class="broadcast_t">语音广播<label>选择喇叭位置</label></view>
  133. <!-- 按钮部分 -->
  134. <view class="trumpet-max-box">
  135. <view @click="trumpetClick(index)" class="trumpet-for-box"
  136. :class="item.type?'trumpet-color-a':'trumpet-color-b'" v-for="(item,index) in trumpetList" :key="index">
  137. <img :src="imagesUrl('commonality/icon_sskz_zc.png')" v-if="!item.type">
  138. <img :src="imagesUrl('commonality/icon_sskz_xz.png')" v-if="item.type">
  139. {{item.deviceName}}
  140. </view>
  141. </view>
  142. <!-- #ifdef MP-WEIXIN -->
  143. <view class="broadcast_m">
  144. <view class="broadcast_m_t"
  145. :class="liveType?'broadcast_m_t_back_a':'broadcast_m_t_back_b'"
  146. @longpress.stop="recordButton" @touchmove.stop="cancelButton" @touchend.stop="sendButton">
  147. {{liveType?'松开发送':'按住说话'}}
  148. </view>
  149. <view class="broadcast_m_b" v-if="!liveType">按住说话,录入广播内容</view>
  150. <view class="broadcast_m_b" v-if="liveType">松开发送,向上滑动取消发送</view>
  151. </view>
  152. <!-- #endif -->
  153. <!-- #ifdef WEB -->
  154. <view class="broadcast_m no-long-press">
  155. <view class="broadcast_m_t no-long-press"
  156. :class="liveType?'broadcast_m_t_back_a':'broadcast_m_t_back_b'"
  157. @touchstart="handleTouchStart"
  158. @touchmove="handleTouchMove"
  159. @touchend="handleTouchEnd"
  160. @touchcancel="handleTouchEnd"
  161. @contextmenu.prevent="handleContextMenu">
  162. </view>
  163. <!-- @longpress.stop="startRecord" @touchmove.stop="delRecord" @touchend.stop="stopRecord" -->
  164. <view class="broadcast_m_b no-long-press" v-if="!liveType">按住说话,录入广播内容</view>
  165. <view class="broadcast_m_b no-long-press" v-if="liveType">松开发送,向上滑动取消发送</view>
  166. </view>
  167. <!-- #endif -->
  168. </view>
  169. </view>
  170. </view>
  171. <view></view>
  172. </view>
  173. </template>
  174. <script>
  175. // #ifdef WEB
  176. import Recorder from 'recorder-core';
  177. import 'recorder-core/src/engine/mp3';
  178. import 'recorder-core/src/engine/mp3-engine';
  179. // #endif
  180. import {
  181. itoOrVideoLimits
  182. } from '@/utils/index'
  183. import $mqtt from '@/utils/mqtt.min.js';
  184. import {
  185. config
  186. } from '@/api/request/config.js'
  187. import {
  188. iotAppSpeakerFindHorn,
  189. iotAppSpeakerPlayVoice
  190. } from '@/pages_manage/api/index.js'
  191. import {
  192. laboratoryBigViewGetBuildByBigView,
  193. laboratoryBigViewSelectTriggerInfo,
  194. laboratoryBigViewGetFloorByBigView,
  195. laboratoryExitLineGetRedisEvacuation,
  196. laboratoryPlanCloseRiskPlan,
  197. laboratoryExitLineExecuteEvacuation,
  198. laboratoryexitLineEndEvacuation,
  199. } from '@/pages_manage/api/index.js'
  200. export default {
  201. data() {
  202. return {
  203. videoCover: uni.getStorageSync('videoCover'),
  204. //页面状态
  205. pageType: "1",
  206. deptIndex: 0,
  207. //院系楼栋数据
  208. buildingList: [],
  209. buildingName: "",
  210. buildingId: "",
  211. //楼层数据
  212. floorList: [],
  213. floorName: "",
  214. floorId: "",
  215. //实验室
  216. fjListArray: [],
  217. //接收参数
  218. subId: "",
  219. adminId: "",
  220. subName: "",
  221. roomNum: "",
  222. title: "",
  223. type: "",
  224. //喇叭数据
  225. trumpetList: [],
  226. //广播相关
  227. liveType: false,
  228. sendLock: true, //发送锁,当为true时上锁,false时解锁发送
  229. // #ifdef MP-WEIXIN
  230. recorderManager: uni.getRecorderManager(),
  231. // #endif
  232. isEvacuate: true, //疏散按钮控制,当为true时候执行疏散
  233. //滑动记录
  234. startPoint: {},
  235. //摄像头信息
  236. deptId: '',
  237. itemData: {
  238. hardwareNUM: '',
  239. name: '',
  240. },
  241. broadcastType: false,
  242. //选中楼栋
  243. checkSubName: "",
  244. address: "",
  245. videoHardwareNUM: [], //实验室和楼道摄像头编码
  246. //新布局地图相关数据
  247. zoomData: null,
  248. mapType: false,
  249. mapList: [],
  250. mapWidth: null, //40边框距离
  251. mapHeight: null, //40边框距离
  252. //MQTT请求参数-预案
  253. mtopic: "lab/risk/plan/change",
  254. //MQTT请求参数-疏散
  255. mtopicOne: "lab/floor/exit/line",
  256. client: {},
  257. groupId: null,
  258. planStatus: false,
  259. warnData: null,
  260. pageData:null,
  261. //H5
  262. recording: false,
  263. recorder: null,
  264. audioBlob: null,
  265. audioPath: null,
  266. //H5 拖拽
  267. touchStartY: 0,
  268. isLongPress: false,
  269. hasMoved: false,
  270. longPressTimer: null,
  271. moveDirection: null,
  272. hasTriggeredMethod3: false // 确保方法3只触发一次
  273. }
  274. },
  275. onLoad(option) {
  276. if (option.item) {
  277. let obj = JSON.parse(decodeURIComponent(option.item));
  278. console.log('obj',obj)
  279. // console.log('obj',obj)
  280. if(obj.type == 'skip'){
  281. // 新实验室列表跳转进入逻辑
  282. this.$set(this, 'pageData', obj);
  283. this.$set(this, 'buildingId', obj.buildId);
  284. this.$set(this, 'deptId', obj.buildId);
  285. this.$set(this, 'floorId', obj.floorId);
  286. this.$set(this, 'subId', obj.subId);
  287. this.$set(this, 'adminId', obj.adminId);
  288. this.$set(this.itemData, 'subjectId', obj.subId);
  289. this.$set(this, 'pageType', 2);
  290. }else{
  291. this.$set(this, 'warnData', obj);
  292. this.$set(this, 'buildingId', obj.buildId);
  293. this.$set(this, 'deptId', obj.buildId);
  294. this.$set(this, 'floorId', obj.floorId);
  295. this.$set(this, 'subId', obj.subId);
  296. this.$set(this, 'adminId', obj.adminId);
  297. this.$set(this.itemData, 'subjectId', obj.subId);
  298. this.$set(this, 'groupId', obj.groupId);
  299. this.$set(this, 'pageType', 2);
  300. }
  301. }
  302. },
  303. onShow() {
  304. // if (this.warnData) {
  305. // this.getDataA();
  306. // } else {
  307. // this.laboratoryBigViewGetBuildByBigView();
  308. // }
  309. this.getDataA();
  310. this.getRedisEvacuation();
  311. // #ifdef MP-WEIXIN
  312. if (this.recorderManager) {
  313. this.recorderManager.stop();
  314. }
  315. // #endif
  316. },
  317. onUnload() {},
  318. methods: {
  319. //跳转进来后的初始化
  320. async getDataA() {
  321. const {
  322. data
  323. } = await laboratoryBigViewGetBuildByBigView({
  324. type: 2
  325. })
  326. if(data.code == 200){
  327. this.$set(this, 'buildingList', data.data);
  328. data.data.forEach((item)=>{
  329. if(this.buildingId == item.id){
  330. this.$set(this,'buildingName',item.name);
  331. }
  332. }),
  333. this.selectTriggerInfo(1);
  334. this.getDataB()
  335. }
  336. },
  337. async getDataB() {
  338. const {
  339. data
  340. } = await laboratoryBigViewGetBuildByBigView({
  341. type: 3,
  342. id: this.deptId
  343. })
  344. if (data.code == 200) {
  345. this.$set(this, 'floorList', data.data);
  346. data.data.forEach((item)=>{
  347. if(this.floorId == item.id){
  348. this.$set(this,'floorName',item.name);
  349. }
  350. }),
  351. this.selectTriggerInfo(2);
  352. this.confirmBtn();
  353. this.getBuildingData();
  354. }
  355. },
  356. //返回按钮
  357. backButton() {
  358. // let self = this;
  359. // this.$set(this, 'pageType', 1);
  360. // this.laboratoryBigViewGetBuildByBigView();
  361. if(this.pageData){
  362. uni.navigateBack();
  363. }else{
  364. uni.redirectTo({
  365. url: "/pages_manage/views/emergencyEvacuationSubList",
  366. });
  367. }
  368. },
  369. //结束预案
  370. closePlan() {
  371. let self = this;
  372. if(!itoOrVideoLimits(this.adminId)){
  373. uni.showToast({
  374. title: '没有相关操作权限,请联系管理员',
  375. icon: "none",
  376. mask: true,
  377. duration: 2000
  378. });
  379. return
  380. }
  381. uni.showModal({
  382. content: '传感器数据监测异常,确定要强制结束预案?关闭报警后,3分钟内系统不再触发预案报警,请核实确认后再执行此操作?',
  383. cancelColor: "#999",
  384. confirmColor: "#0183FA",
  385. success: function(res) {
  386. if (res.confirm) {
  387. self.closeRiskPlan();
  388. } else if (res.cancel) {}
  389. }
  390. });
  391. },
  392. //获取视频数据
  393. getVideo(){
  394. if(!itoOrVideoLimits(this.adminId)){
  395. uni.showToast({
  396. title: '没有相关操作权限,请联系管理员',
  397. icon: "none",
  398. mask: true,
  399. duration: 2000
  400. });
  401. return
  402. }
  403. let obj = {
  404. type:5,
  405. floorId:this.floorId,
  406. subId:this.subId,
  407. }
  408. uni.navigateTo({
  409. url: '/pages_manage/views/laboratory/videoPlayer?item='+encodeURIComponent(JSON.stringify(obj))
  410. });
  411. },
  412. async closeRiskPlan() {
  413. // console.log('this.groupId',this.groupId);
  414. const {
  415. data
  416. } = await laboratoryPlanCloseRiskPlan({
  417. eventId: this.groupId
  418. });
  419. if (data.code == 200) {
  420. uni.showToast({
  421. title: '操作成功',
  422. icon: "none",
  423. mask: true,
  424. duration: 2000
  425. });
  426. this.selectTriggerInfo();
  427. }
  428. },
  429. //全屏疏散页面
  430. goAllPage() {
  431. let obj = {
  432. buildingId: this.buildingId,
  433. floorId: this.floorId,
  434. type: 1,
  435. }
  436. uni.navigateTo({
  437. url: '/pages_manage/views/emergencyEvacuationBigFullScreen?item=' + encodeURIComponent(JSON
  438. .stringify(obj)),
  439. });
  440. },
  441. //获取楼栋数据
  442. async laboratoryBigViewGetBuildByBigView(option) {
  443. const {
  444. data
  445. } = await laboratoryBigViewGetBuildByBigView({
  446. type: 2
  447. })
  448. this.$set(this, 'buildingList', data.data);
  449. this.selectTriggerInfo(1);
  450. },
  451. //获取楼层数据
  452. async getBuilding(buildingId) {
  453. const {
  454. data
  455. } = await laboratoryBigViewGetBuildByBigView({
  456. type: 3,
  457. id: buildingId
  458. })
  459. this.$set(this, 'floorList', data.data);
  460. this.$set(this, 'floorName', "");
  461. this.$set(this, 'floorId', "");
  462. this.$set(this, 'fjListArray', []);
  463. this.$set(this, 'subName', "");
  464. this.$set(this, 'subId', "");
  465. this.selectTriggerInfo(2);
  466. },
  467. //楼栋选中
  468. buildingChange(e) {
  469. this.$set(this, 'buildingName', this.buildingList[e.detail.value].name);
  470. this.$set(this, 'buildingId', this.buildingList[e.detail.value].id);
  471. this.$set(this, 'deptId', this.buildingList[e.detail.value].id);
  472. this.$set(this, 'floorId', null);
  473. this.$set(this, 'floorName', null);
  474. this.$set(this, 'subId', null);
  475. this.$set(this, 'subName', null);
  476. this.$set(this.itemData, 'subjectId', null);
  477. this.$set(this, 'floorList', []);
  478. this.$set(this, 'fjListArray', []);
  479. this.getBuilding(this.buildingList[e.detail.value].id);
  480. },
  481. //楼层选中
  482. floorChange(e) {
  483. this.$set(this, 'floorName', this.floorList[e.detail.value].name);
  484. this.$set(this, 'floorId', this.floorList[e.detail.value].id);
  485. this.$set(this, 'subId', null);
  486. this.$set(this, 'subName', null);
  487. this.$set(this.itemData, 'subjectId', null);
  488. this.$set(this, 'fjListArray', []);
  489. this.getBuildingData();
  490. },
  491. //实验室选择
  492. fjListChange(e) {
  493. this.$set(this, 'subName', this.fjListArray[e.detail.value].subName);
  494. this.$set(this, 'subId', this.fjListArray[e.detail.value].subId);
  495. this.$set(this.itemData, 'subjectId', this.fjListArray[e.detail.value].subId);
  496. },
  497. shadeTypeClick() {
  498. if(!itoOrVideoLimits(this.adminId)){
  499. uni.showToast({
  500. title: '没有相关操作权限,请联系管理员',
  501. icon: "none",
  502. mask: true,
  503. duration: 2000
  504. });
  505. return
  506. }
  507. this.broadcastType = !this.broadcastType
  508. },
  509. //获取预案数据
  510. async selectTriggerInfo(type) {
  511. let self = this;
  512. const {
  513. data
  514. } = await laboratoryBigViewSelectTriggerInfo();
  515. if (data.code == 200) {
  516. if (type == 1) {
  517. //标记楼栋
  518. for (let o = 0; o < self.buildingList.length; o++) {
  519. for (let i = 0; i < data.data.length; i++) {
  520. if (data.data[i].buildId == self.buildingList[o].id) {
  521. self.buildingList[o].name = self.textFiltration(self.buildingList[o].name)
  522. self.buildingList[o].name = '(预案发生) ' + self.buildingList[o].name
  523. }
  524. }
  525. }
  526. }
  527. if (type == 2) {
  528. //标记楼层
  529. for (let o = 0; o < self.floorList.length; o++) {
  530. for (let i = 0; i < data.data.length; i++) {
  531. if (data.data[i].floorId == self.floorList[o].id) {
  532. self.floorList[o].name = self.textFiltration(self.floorList[o].name)
  533. self.floorList[o].name = '(预案发生) ' + self.floorList[o].name
  534. }
  535. }
  536. }
  537. }
  538. if (type == 3) {
  539. //标记实验室
  540. let bigNum = 0;
  541. for (let o = 0; o < self.fjListArray.length; o++) {
  542. let num = 0;
  543. for (let i = 0; i < data.data.length; i++) {
  544. if (data.data[i].subId == self.fjListArray[o].subId) {
  545. num++
  546. bigNum++
  547. self.$set(this, 'groupId', data.data[i].eventId)
  548. self.fjListArray[o].subName = self.textFiltration(self.fjListArray[o].subName)
  549. self.fjListArray[o].subName = '(预案发生) ' + self.fjListArray[o].subName
  550. }
  551. }
  552. if (num == 0) {
  553. self.fjListArray[o].subName = self.textFiltration(self.fjListArray[o].subName)
  554. }
  555. }
  556. if (bigNum != 0) {
  557. self.$set(self, 'planStatus', true)
  558. } else {
  559. self.$set(self, 'planStatus', false)
  560. }
  561. for (let o = 0; o < self.mapList.length; o++) {
  562. if (self.mapList[o].type == 1) {
  563. let num = 0;
  564. for (let i = 0; i < data.data.length; i++) {
  565. if (data.data[i].subId == self.mapList[o].subId) {
  566. num++
  567. }
  568. }
  569. if (num != 0) {
  570. self.mapList[o].policeType = true;
  571. } else {
  572. self.mapList[o].policeType = false;
  573. }
  574. }
  575. }
  576. }
  577. this.$forceUpdate();
  578. }
  579. },
  580. getAppExitLine() {
  581. let list = [{
  582. type: "lab/exit/line"
  583. }, {
  584. type: "lab/fireDevice/Warn/"
  585. }];
  586. getApp().appMqttOn(1, list);
  587. },
  588. //点击选择喇叭
  589. trumpetClick(index) {
  590. this.trumpetList[index].type = !this.trumpetList[index].type
  591. // let _this = this;
  592. // if (_this.trumpetList[index].type == true) {
  593. // _this.trumpetList.forEach(function(item2) {
  594. // if (item2.deviceSn == _this.trumpetList[index].deviceSn) {
  595. // item2.type = true
  596. // } else {
  597. // item2.type = false
  598. // }
  599. // })
  600. // }
  601. },
  602. //录制
  603. recordButton(e) {
  604. // console.log("按下")
  605. let self = this;
  606. let num = 0;
  607. for (let i = 0; i < self.trumpetList.length; i++) {
  608. if (self.trumpetList[i].type) {
  609. num++
  610. }
  611. }
  612. if (num == 0) {
  613. uni.showToast({
  614. title: '请选择喇叭',
  615. icon: "none",
  616. mask: true,
  617. duration: 2000
  618. });
  619. return
  620. }
  621. this.liveType = true;
  622. // console.log('录制', e)
  623. this.startPoint = e.touches[0]; //记录长按时开始点信息,后面用于计算上划取消时手指滑动的距离。
  624. const options = {
  625. duration: 10000,
  626. sampleRate: 16000,
  627. numberOfChannels: 1,
  628. encodeBitRate: 48000,
  629. format: 'mp3',
  630. frameSize: 50
  631. }
  632. this.recorderManager.start(options); //开始录音
  633. this.recorderManager.onStart(() => {
  634. // console.log('recorder start')
  635. })
  636. this.recorderManager.onError((res) => {
  637. // console.log(res);
  638. })
  639. uni.showToast({
  640. title: "正在录音,上划取消发送",
  641. icon: "none",
  642. duration: 60000 //先定义个60秒,后面可以手动调用uni.hideToast()隐藏
  643. });
  644. this.sendLock = false; //长按时是不上锁的。
  645. },
  646. //取消
  647. cancelButton(e) {
  648. // console.log("移动")
  649. let self = this;
  650. let num = 0;
  651. for (let i = 0; i < self.trumpetList.length; i++) {
  652. if (self.trumpetList[i].type) {
  653. num++
  654. }
  655. }
  656. if (num == 0) {
  657. return
  658. }
  659. this.liveType = false;
  660. // console.log('取消', e)
  661. let moveLenght = e.touches[e.touches.length - 1].clientY - this.startPoint.clientY; //移动距离
  662. if (Math.abs(moveLenght) > 50) {
  663. uni.showToast({
  664. title: "松开手指,取消发送",
  665. icon: "none",
  666. duration: 60000
  667. });
  668. this.sendLock = true; //触发了上滑取消发送,上锁
  669. } else {
  670. uni.showToast({
  671. title: "正在录音,上划取消发送",
  672. icon: "none",
  673. duration: 60000
  674. });
  675. this.sendLock = false; //上划距离不足,依然可以发送,不上锁
  676. }
  677. },
  678. //发送
  679. sendButton(e) {
  680. // console.log("松开")
  681. let self = this;
  682. let num = 0;
  683. for (let i = 0; i < self.trumpetList.length; i++) {
  684. if (self.trumpetList[i].type) {
  685. num++
  686. }
  687. }
  688. if (num == 0) {
  689. return
  690. }
  691. this.liveType = false;
  692. // console.log('发送', e)
  693. uni.hideToast(); //结束录音、隐藏Toast提示框
  694. this.recorderManager.stop(); //结束录音
  695. this.recorderManager.onStop((res) => {
  696. if (!this.sendLock) {
  697. // console.log('1', this.recorderManager)
  698. this.uploadImg(res.tempFilePath);
  699. }
  700. // console.log('停止录音', res.tempFilePath)
  701. // console.log("sendLock", this.sendLock);
  702. })
  703. },
  704. //上传MP3
  705. async uploadImg(tempFilePaths) {
  706. var self = this;
  707. uni.uploadFile({
  708. url: config.base_url + '/system/file/upload', //仅为示例,非真实的接口地址
  709. header: {
  710. 'Authorization': uni.getStorageSync('token')
  711. },
  712. filePath: tempFilePaths,
  713. name: 'file',
  714. formData: {
  715. 'user': 'test'
  716. },
  717. success: (uploadFileRes) => {
  718. let res = JSON.parse(uploadFileRes.data);
  719. if (res.code == 200) {
  720. // console.log("上传成功", res)
  721. let url = uni.getStorageSync('fileBrowseEnvironment') + '/' + res.data.url
  722. self.iotAppSpeakerPlayVoice(url);
  723. } else {
  724. uni.showToast({
  725. title: res.msg,
  726. icon: "none",
  727. mask: true,
  728. duration: 2000
  729. });
  730. }
  731. },
  732. fail: err => {
  733. uni.hideLoading()
  734. },
  735. complete: () => {}
  736. });
  737. },
  738. //发送语音
  739. async iotAppSpeakerPlayVoice(text) {
  740. let self = this;
  741. let list = [];
  742. for (let i = 0; i < self.trumpetList.length; i++) {
  743. if (self.trumpetList[i].type) {
  744. list.push(self.trumpetList[i].deviceNo)
  745. }
  746. }
  747. let obj = {
  748. deviceNo: list.join(','),
  749. voiceUrls: text,
  750. cycle: 1,
  751. level:1000,
  752. }
  753. const {
  754. data
  755. } = await iotAppSpeakerPlayVoice(obj)
  756. if (data.code == 200) {
  757. uni.showToast({
  758. title: '发送成功',
  759. icon: "none",
  760. mask: true,
  761. duration: 2000
  762. });
  763. }
  764. },
  765. //监听应急疏散数据变更
  766. getMqttLineData(val) {
  767. // console.log('收到疏散MQTT')
  768. let self = this;
  769. if (val.EXIT_LINE_MESSAGE) {
  770. // console.log('数据改变')
  771. this.evacuate();
  772. } else {
  773. // console.log('应急疏散已结束')
  774. uni.showToast({
  775. title: '应急疏散已结束',
  776. icon: "none",
  777. mask: true,
  778. duration: 2000
  779. });
  780. setTimeout(function() {
  781. uni.navigateBack();
  782. }, 2000);
  783. }
  784. },
  785. /* 确认 */
  786. confirmBtn() {
  787. if (!this.subId) {
  788. uni.showToast({
  789. title: '请选择实验室',
  790. icon: "none",
  791. mask: true,
  792. duration: 2000
  793. });
  794. return
  795. }
  796. this.$set(this, 'pageType', 2);
  797. this.getDeviceList();
  798. this.getRedisEvacuation();
  799. },
  800. //执行疏散
  801. async lineEvacuate() {
  802. let obj = {
  803. buildingId: this.buildingId,
  804. floorId: this.floorId,
  805. type: 2,
  806. }
  807. uni.navigateTo({
  808. url: '/pages_manage/views/emergencyEvacuationBigFullScreen?item=' + encodeURIComponent(JSON
  809. .stringify(obj)),
  810. });
  811. },
  812. //获取喇叭列表
  813. async getDeviceList() {
  814. let obj = {
  815. subId: this.itemData.subjectId,
  816. floorId: this.floorId,
  817. };
  818. const {
  819. data
  820. } = await iotAppSpeakerFindHorn(obj)
  821. if (data.code == 200) {
  822. for (let i = 0; i < data.data.length; i++) {
  823. data.data[i].type = false;
  824. }
  825. this.$set(this, 'trumpetList', data.data)
  826. }
  827. },
  828. //摄像头切换
  829. scrollBoxClick(index) {
  830. this.videoIndex = index;
  831. },
  832. /*新疏散相关接口*/
  833. //地图数据
  834. async getBuildingData() {
  835. let self = this;
  836. const {
  837. data
  838. } = await laboratoryBigViewGetFloorByBigView({
  839. id: this.floorId
  840. })
  841. const hex2Rgba = (bgColor) => {
  842. let color = bgColor.slice(1); // 去掉'#'号
  843. let rgba = [
  844. parseInt("0x" + color.slice(0, 2)),
  845. parseInt("0x" + color.slice(2, 4)),
  846. parseInt("0x" + color.slice(4, 6)),
  847. 0.6
  848. ];
  849. return "rgba(" + rgba.toString() + ")";
  850. };
  851. // console.log('data', data)
  852. if (data.code == 200) {
  853. if (data.data[0].buildLayoutVoList[0]) {
  854. let list = JSON.parse(data.data[0].labExitLineVo.layoutJoinData)
  855. this.zoomCalculate(list, 348, 668);
  856. for (let i = 0; i < list.length; i++) {
  857. if (list[i].type == '2') {
  858. //楼道
  859. for (let o = 0; o < list[i].lightList.length; o++) {
  860. list[i].lightList[o].openType = false;
  861. }
  862. } else if (list[i].type == '1') {
  863. for (let o = 0; o < data.data[0].buildLayoutVoList.length; o++) {
  864. if (list[i].key == data.data[0].buildLayoutVoList[o].pointName) {
  865. list[i].id = data.data[0].buildLayoutVoList[o].id;
  866. list[i].buildId = data.data[0].buildLayoutVoList[o].buildId;
  867. list[i].floorId = data.data[0].buildLayoutVoList[o].floorId;
  868. list[i].roomType = data.data[0].buildLayoutVoList[o].roomType;
  869. list[i].roomName = data.data[0].buildLayoutVoList[o].roomName;
  870. list[i].roomNum = data.data[0].buildLayoutVoList[o].roomNum;
  871. list[i].subName = data.data[0].buildLayoutVoList[o].subName;
  872. list[i].subId = data.data[0].buildLayoutVoList[o].subId;
  873. list[i].online = data.data[0].buildLayoutVoList[o].online;
  874. list[i].loginAdmin = data.data[0].buildLayoutVoList[o].loginAdmin;
  875. list[i].levelColor = data.data[0].buildLayoutVoList[o].levelColor?hex2Rgba(data.data[0].buildLayoutVoList[o].levelColor):'';
  876. list[i].policeType = false;
  877. }
  878. }
  879. } else if (list[i].type == 3) {
  880. list[i].roomCheckType = false;
  881. }
  882. }
  883. let subList = [];
  884. for (let o = 0; o < data.data[0].buildLayoutVoList.length; o++) {
  885. subList.push(data.data[0].buildLayoutVoList[o])
  886. // if (self.subId == data.data[0].buildLayoutVoList[o].subId) {
  887. // self.$set(self, 'checkSubName', data.data[0].buildLayoutVoList[o].subName);
  888. // self.$set(self, 'address', data.data.labExitLineVo.buildName + '' + data.data[0]
  889. // .labExitLineVo.floorName);
  890. // }
  891. }
  892. this.$set(this, 'fjListArray', subList);
  893. subList.forEach((item)=>{
  894. if(this.subId == item.subId){
  895. this.$set(this,'roomNum',item.roomNum);
  896. this.$set(this,'subName',item.subName);
  897. }
  898. })
  899. this.$set(this, 'mapList', JSON.parse(JSON.stringify(list)));
  900. // this.$set(this, 'shadeMapList', JSON.parse(JSON.stringify(list)));
  901. this.$set(this, 'mapType', true);
  902. this.offMQTT('on');
  903. this.selectTriggerInfo(3);
  904. }
  905. setTimeout(function() {
  906. self.getRedisEvacuation();
  907. }, 500);
  908. }
  909. },
  910. //获取疏散数据
  911. async getRedisEvacuation() {
  912. let self = this;
  913. let obj = {
  914. buildId: this.buildingId,
  915. floorId: this.floorId,
  916. }
  917. const {
  918. data
  919. } = await laboratoryExitLineGetRedisEvacuation(obj)
  920. if (data.code == 200) {
  921. if (data.data.doorPointNames) {
  922. this.$set(this, 'isEvacuate', false);
  923. for (let o = 0; o < self.mapList.length; o++) {
  924. if (self.mapList[o].type == 2) {
  925. for (let x = 0; x < self.mapList[o].lightList.length; x++) {
  926. let num = 0;
  927. for (let i = 0; i < data.data.lightPointSet.length; i++) {
  928. if (data.data.lightPointSet[i]) { //处理后端返回的异常的NULL
  929. if (self.mapList[o].lightList[x].key == data.data.lightPointSet[i].key) {
  930. num++
  931. }
  932. }
  933. }
  934. self.mapList[o].lightList[x].openType = num != 0;
  935. }
  936. }
  937. if (self.mapList[o].type == 3) {
  938. let age = 0;
  939. for (let i = 0; i < data.data.doorPointNames.length; i++) {
  940. if (data.data.doorPointNames[i] == self.mapList[o].key) {
  941. age++
  942. }
  943. }
  944. self.mapList[o].roomCheckType = age != 0;
  945. }
  946. }
  947. } else {
  948. this.$set(this, 'isEvacuate', true);
  949. for (let o = 0; o < self.mapList.length; o++) {
  950. if (self.mapList[o].type == 2) {
  951. for (let x = 0; x < self.mapList[o].lightList.length; x++) {
  952. self.mapList[o].lightList[x].openType = false;
  953. }
  954. }
  955. if (self.mapList[o].type == 3) {
  956. self.mapList[o].roomCheckType = false;
  957. }
  958. }
  959. }
  960. };
  961. },
  962. //缩放计算
  963. zoomCalculate(list, height, width) {
  964. let maxWidth = 0
  965. let maxHeight = 0
  966. let zoomData = 1;
  967. for (let i = 0; i < list.length; i++) {
  968. if ((list[i].x + list[i].w) > maxWidth) {
  969. maxWidth = list[i].x + list[i].w
  970. }
  971. if ((list[i].y + list[i].h) > maxHeight) {
  972. maxHeight = list[i].y + list[i].h
  973. }
  974. }
  975. //处理等值数据
  976. if (maxHeight == height) {
  977. maxHeight--
  978. }
  979. if (maxWidth == width) {
  980. maxWidth--
  981. }
  982. this.$set(this, 'mapWidth', maxWidth);
  983. this.$set(this, 'mapHeight', maxHeight);
  984. //缩放判断
  985. let zoomNumOne = height / maxHeight;
  986. if (parseInt(this.accMul(zoomNumOne, maxHeight)) <= height && parseInt(this.accMul(zoomNumOne,
  987. maxWidth)) <= width) {
  988. zoomData = zoomNumOne;
  989. this.$set(this, 'zoomData', zoomNumOne);
  990. }
  991. let zoomNumTwo = width / maxWidth;
  992. if (parseInt(this.accMul(zoomNumTwo, maxHeight)) <= height && parseInt(this.accMul(zoomNumTwo,
  993. maxWidth)) <= width) {
  994. zoomData = zoomNumTwo;
  995. this.$set(this, 'zoomData', zoomNumTwo);
  996. }
  997. },
  998. accMul(arg1, arg2) {
  999. var m = 0,
  1000. s1 = arg1.toString(),
  1001. s2 = arg2.toString();
  1002. try {
  1003. m += s1.split(".")[1].length
  1004. } catch (e) {}
  1005. try {
  1006. m += s2.split(".")[1].length
  1007. } catch (e) {}
  1008. return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
  1009. },
  1010. //结束疏散
  1011. evacuationButton() {
  1012. let self = this;
  1013. if(!itoOrVideoLimits(this.adminId)){
  1014. uni.showToast({
  1015. title: '没有相关操作权限,请联系管理员',
  1016. icon: "none",
  1017. mask: true,
  1018. duration: 2000
  1019. });
  1020. return
  1021. }
  1022. if (this.isEvacuate) {
  1023. let obj = {
  1024. buildingId: this.buildingId,
  1025. floorId: this.floorId,
  1026. subId: this.subId,
  1027. type: 2,
  1028. }
  1029. uni.navigateTo({
  1030. url: '/pages_manage/views/emergencyEvacuationBigFullScreen?item=' + encodeURIComponent(JSON
  1031. .stringify(obj)),
  1032. });
  1033. } else {
  1034. uni.showModal({
  1035. content: '确认' + (this.isEvacuate ? '执行' : '结束') + '疏散吗?',
  1036. cancelColor: "#999",
  1037. confirmColor: "#0183FA",
  1038. success: function(res) {
  1039. if (res.confirm) {
  1040. if (self.isEvacuate) {
  1041. self.executeEvacuation();
  1042. } else {
  1043. self.endEvacuation();
  1044. }
  1045. // console.log('用户点击确定');
  1046. } else if (res.cancel) {
  1047. // console.log('用户点击取消');
  1048. }
  1049. }
  1050. });
  1051. }
  1052. },
  1053. //开始疏散
  1054. async executeEvacuation() {
  1055. let self = this;
  1056. let doorPointNames = [];
  1057. for (let i = 0; i < self.mapList.length; i++) {
  1058. if (self.mapList[i].type == 3) {
  1059. doorPointNames.push(self.mapList[i].key)
  1060. }
  1061. }
  1062. let obj = {
  1063. buildId: this.buildingId,
  1064. floorId: this.floorId,
  1065. subId: this.subId,
  1066. badPointNames: [],
  1067. doorPointNames: doorPointNames,
  1068. }
  1069. const {
  1070. data
  1071. } = await laboratoryExitLineExecuteEvacuation(obj)
  1072. // console.log('data', data)
  1073. if (data.code == 200) {
  1074. this.$set(this, 'isEvacuate', false);
  1075. uni.showToast({
  1076. title: '执行成功',
  1077. icon: "none",
  1078. mask: true,
  1079. duration: 2000
  1080. });
  1081. }
  1082. },
  1083. //结束疏散
  1084. async endEvacuation() {
  1085. let self = this;
  1086. let obj = {
  1087. buildId: this.buildingId,
  1088. floorId: this.floorId,
  1089. }
  1090. const {
  1091. data
  1092. } = await laboratoryexitLineEndEvacuation(obj)
  1093. // console.log('data', data)
  1094. if (data.code == 200) {
  1095. this.$set(this, 'isEvacuate', true);
  1096. uni.showToast({
  1097. title: '执行成功',
  1098. icon: "none",
  1099. mask: true,
  1100. duration: 2000
  1101. });
  1102. if (this.warnData) {
  1103. this.getDataA();
  1104. } else {
  1105. this.laboratoryBigViewGetBuildByBigView();
  1106. }
  1107. this.getRedisEvacuation();
  1108. }
  1109. },
  1110. videoErrorCallback(e) {
  1111. //console.log("播放失败",e);
  1112. // uni.showToast({
  1113. // title: '视频播放失败',
  1114. // icon:"none",
  1115. // mask:true,
  1116. // duration: 3000
  1117. // });
  1118. },
  1119. //过滤'预案发生'标记文字并返回数据
  1120. textFiltration(str) {
  1121. if(str){
  1122. if (str.indexOf("(预案发生)") != -1) {
  1123. return str.slice(str.indexOf(")") + 1);
  1124. } else {
  1125. return str
  1126. }
  1127. }else{
  1128. return str
  1129. }
  1130. },
  1131. //MQTT订阅
  1132. sensorMQTT() {
  1133. let self = this;
  1134. this.client = $mqtt.connect(
  1135. // #ifdef WEB
  1136. 'wss://' + uni.getStorageSync('mqttUrl')
  1137. // #endif
  1138. // #ifdef MP-WEIXIN
  1139. 'wxs://' + uni.getStorageSync('mqttUrl')
  1140. // #endif
  1141. , {
  1142. username: uni.getStorageSync('mqttUser'),
  1143. password: uni.getStorageSync('mqttPassword')
  1144. });
  1145. this.client.on("connect", e => {
  1146. this.client.subscribe(this.mtopic, (err) => {
  1147. if (!err) {
  1148. console.log("预案订阅成功:" + this.mtopic);
  1149. } else {
  1150. // console.log("连接错误:" + err);
  1151. }
  1152. });
  1153. this.client.subscribe(this.mtopicOne, (err) => {
  1154. if (!err) {
  1155. console.log("疏散订阅成功:" + this.mtopicOne);
  1156. } else {
  1157. // console.log("连接错误:" + err);
  1158. }
  1159. });
  1160. });
  1161. this.client.on("message", (topic, message) => {
  1162. // console.log('message', message);
  1163. // console.log('topic,', topic);
  1164. if (message) {
  1165. if (topic == this.mtopic) {
  1166. //预案触发
  1167. this.selectTriggerInfo(3);
  1168. } else if (topic == this.mtopicOne) {
  1169. //疏散触发
  1170. this.getRedisEvacuation();
  1171. }
  1172. }
  1173. });
  1174. },
  1175. //取消订阅关闭MQTT连接
  1176. offMQTT(type) {
  1177. let self = this;
  1178. if (self.client.unsubscribe) {
  1179. self.client.unsubscribe(self.mtopicOne, error => {
  1180. if (error) {
  1181. // console.log('mqtt关闭连接错误:', error)
  1182. }
  1183. })
  1184. self.client.unsubscribe(self.mtopic, error => {
  1185. if (error) {
  1186. // console.log('mqtt关闭连接错误:', error)
  1187. }
  1188. })
  1189. self.client.end();
  1190. this.$set(this, 'client', {});
  1191. }
  1192. //判断传入参数如果存在 发起一次新的连接
  1193. if (type) {
  1194. this.sensorMQTT();
  1195. }
  1196. },
  1197. // #ifdef WEB
  1198. /* H5 */
  1199. async initRecorder() {
  1200. try {
  1201. // 获取麦克风权限
  1202. await navigator.mediaDevices.getUserMedia({ audio: true });
  1203. this.recorder = new Recorder({
  1204. type: "mp3", // 输出格式
  1205. bitRate: 64, // 降低比特率提升兼容性
  1206. // 不指定 sampleRate,让浏览器使用系统默认值(iOS 兼容性要求)
  1207. });
  1208. this.recorder.open(() => {
  1209. // 初始化成功,继续 startRecord 流程
  1210. this.startRecord();
  1211. }, (error) => {
  1212. console.error("录音器初始化失败:", error);
  1213. uni.showToast({
  1214. title: '麦克风权限获取失败,请允许麦克风权限',
  1215. icon: "none",
  1216. mask: true,
  1217. duration: 2000
  1218. });
  1219. });
  1220. } catch (err) {
  1221. console.error("获取麦克风失败:", err);
  1222. uni.showToast({
  1223. title: '请允许麦克风权限',
  1224. icon: "none",
  1225. mask: true,
  1226. duration: 2000
  1227. });
  1228. }
  1229. },
  1230. // 开始录音
  1231. async startRecord() {
  1232. let self = this;
  1233. if (!this.recorder) {
  1234. await this.initRecorder();
  1235. // this.startRecord()
  1236. return;
  1237. }
  1238. let num = 0;
  1239. for (let i = 0; i < self.trumpetList.length; i++) {
  1240. if (self.trumpetList[i].type) {
  1241. num++
  1242. }
  1243. }
  1244. if (num == 0) {
  1245. uni.showToast({
  1246. title: '请选择喇叭',
  1247. icon: "none",
  1248. mask: true,
  1249. duration: 2000
  1250. });
  1251. return
  1252. }
  1253. this.recorder.start();
  1254. this.recording = true;
  1255. this.liveType = true;
  1256. uni.showToast({ title: "录音开始", icon: "none" });
  1257. },
  1258. // 停止录音
  1259. stopRecord() {
  1260. if (!this.recorder || !this.recording) return;
  1261. this.recorder.stop((blob, duration) => {
  1262. this.recording = false;
  1263. this.liveType = false;
  1264. this.audioBlob = blob;
  1265. // 生成临时文件路径
  1266. this.audioPath = URL.createObjectURL(blob);
  1267. this.uploadAudio();
  1268. }, (error) => {
  1269. console.error("录音失败:", error);
  1270. uni.showToast({ title: "录音失败", icon: "none" });
  1271. });
  1272. },
  1273. delRecord(){
  1274. this.recorder.stop((blob, duration) => {
  1275. this.recording = false;
  1276. this.liveType = false;
  1277. this.audioBlob = null;
  1278. this.audioPath = null;
  1279. })
  1280. },
  1281. // 上传录音文件
  1282. uploadAudio() {
  1283. let self = this;
  1284. if (!this.audioBlob) return;
  1285. // 1. 通过fetch获取Blob数据
  1286. fetch(this.audioPath)
  1287. .then(response => response.blob())
  1288. .then(blob => {
  1289. // 2. 将Blob转换为File对象
  1290. const file = new File([blob], 'audio.mp3', { type: 'audio/mp3' });
  1291. // console.log('file',file);
  1292. // 3. 使用uni.uploadFile上传
  1293. uni.uploadFile({
  1294. url: config.base_url + '/system/file/upload',
  1295. header: {
  1296. 'Authorization': uni.getStorageSync('token')
  1297. },
  1298. file: file,
  1299. name: 'file',
  1300. formData: {
  1301. 'user': 'test'
  1302. },
  1303. success: (res) => {
  1304. // #ifdef WEB
  1305. let obj = JSON.parse(res.data);
  1306. // console.log('上传成功', obj);
  1307. let url = uni.getStorageSync('fileBrowseEnvironment') + '/' + obj.data.url
  1308. // #endif
  1309. // #ifdef MP-WEIXIN
  1310. // console.log('上传成功', res);
  1311. let url = uni.getStorageSync('fileBrowseEnvironment') + '/' + res.data.url
  1312. // #endif
  1313. // console.log('url=====',url)
  1314. self.iotAppSpeakerPlayVoice(url);
  1315. },
  1316. fail: (err) => {
  1317. console.error('上传失败', err);
  1318. uni.showToast({
  1319. title: res.msg,
  1320. icon: "none",
  1321. mask: true,
  1322. duration: 2000
  1323. });
  1324. }
  1325. });
  1326. })
  1327. .catch(error => {
  1328. console.error('获取Blob数据失败', error);
  1329. });
  1330. },
  1331. //H5 拖拽
  1332. // 触摸开始
  1333. handleTouchStart(event) {
  1334. // 彻底阻止所有默认行为
  1335. event.preventDefault();
  1336. event.stopPropagation();
  1337. this.touchStartY = event.touches[0].clientY;
  1338. this.hasMoved = false;
  1339. this.moveDirection = null;
  1340. this.hasTriggeredMethod3 = false;
  1341. // 设置长按定时器
  1342. this.longPressTimer = setTimeout(() => {
  1343. this.isLongPress = true;
  1344. this.startRecord(); // 执行方法1
  1345. }, 300); // 300ms触发长按
  1346. },
  1347. // 触摸移动
  1348. handleTouchMove(event) {
  1349. // 彻底阻止所有默认行为
  1350. event.preventDefault();
  1351. event.stopPropagation();
  1352. if (!this.isLongPress) return;
  1353. const currentY = event.touches[0].clientY;
  1354. const deltaY = currentY - this.touchStartY;
  1355. // 检测滑动方向(向上滑动为负值)
  1356. if (Math.abs(deltaY) > 75) { // 增加阈值避免误触
  1357. this.hasMoved = true;
  1358. this.moveDirection = deltaY < 0 ? 'up' : 'down';
  1359. // 向上滑动执行方法3(确保只触发一次)
  1360. if (this.moveDirection === 'up' && !this.hasTriggeredMethod3) {
  1361. this.hasTriggeredMethod3 = true;
  1362. this.delRecord();
  1363. }
  1364. }
  1365. },
  1366. // 触摸结束
  1367. handleTouchEnd() {
  1368. // 清除长按定时器
  1369. clearTimeout(this.longPressTimer);
  1370. if (this.isLongPress) {
  1371. this.stopRecord(); // 执行方法2
  1372. }
  1373. // 重置状态
  1374. this.isLongPress = false;
  1375. this.hasMoved = false;
  1376. this.moveDirection = null;
  1377. },
  1378. // 关键:禁用上下文菜单(长按菜单)
  1379. handleContextMenu(e) {
  1380. e.preventDefault();
  1381. return false;
  1382. },
  1383. // #endif
  1384. },
  1385. onHide() {
  1386. //清除定时器
  1387. let self = this;
  1388. self.offMQTT();
  1389. },
  1390. beforeDestroy() {
  1391. //清除定时器
  1392. let self = this;
  1393. self.offMQTT();
  1394. },
  1395. }
  1396. </script>
  1397. <style lang="stylus" scoped>
  1398. @import '@/api/request/imagesUrl.styl';
  1399. #emergencyEvacuationBig {
  1400. height: 100%;
  1401. width: 100%;
  1402. display: flex;
  1403. flex-direction: column;
  1404. overflow-y: scroll;
  1405. .setUpEvacuation {
  1406. flex: 1;
  1407. display: flex;
  1408. flex-direction: column;
  1409. overflow-y: scroll;
  1410. .evacuation-max-box {
  1411. width: 710rpx;
  1412. margin: 20rpx 20rpx;
  1413. background: #fff;
  1414. border-radius: 20rpx;
  1415. padding: 20rpx 0;
  1416. .picker-max-box {
  1417. .picker-title-box {
  1418. padding: 0 20rpx;
  1419. display: flex;
  1420. view {
  1421. line-height: 80rpx;
  1422. font-size: 28rpx;
  1423. }
  1424. view:nth-child(1) {
  1425. color: red;
  1426. }
  1427. view:nth-child(2) {}
  1428. view:nth-child(3) {
  1429. color: #999;
  1430. }
  1431. }
  1432. .picker-min-box {
  1433. display: flex;
  1434. height: 80rpx;
  1435. width: 667rpx;
  1436. border: 1rpx solid #a2a2a2;
  1437. border-radius: 10rpx;
  1438. margin: 0 20rpx;
  1439. view {
  1440. flex: 1;
  1441. line-height: 80rpx;
  1442. padding: 0 20rpx;
  1443. color: #999;
  1444. font-size: 28rpx;
  1445. overflow: hidden;
  1446. }
  1447. img {
  1448. width: 24rpx;
  1449. height: 12rpx;
  1450. margin: 35rpx 23rpx;
  1451. }
  1452. }
  1453. }
  1454. }
  1455. }
  1456. .implementEvacuation {
  1457. flex: 1;
  1458. display: flex;
  1459. flex-direction: column;
  1460. overflow-y: scroll;
  1461. .evacuation-max-box {
  1462. width: 710rpx;
  1463. margin: 20rpx 20rpx;
  1464. /* background #fff */
  1465. border-radius: 20rpx;
  1466. padding: 20rpx 0 30rpx;
  1467. .evacuation-title-box {
  1468. // height:150rpx;
  1469. //border-bottom:1rpx solid #dedede;
  1470. background: #FFFFFF;
  1471. border-radius: 20rpx;
  1472. padding: 34rpx 22rpx;
  1473. box-sizing: border-box;
  1474. display: flex;
  1475. .evacuation-title-left {
  1476. flex: 1;
  1477. .evacuation-title-name-box {
  1478. font-size: 30rpx;
  1479. font-family: PingFang SC;
  1480. font-weight: 500;
  1481. color: #333333;
  1482. line-height: 30rpx;
  1483. }
  1484. .site {
  1485. font-size: 28rpx;
  1486. font-family: PingFang SC;
  1487. font-weight: 500;
  1488. color: #999999;
  1489. line-height: 30rpx;
  1490. margin-top: 32rpx;
  1491. display: flex;
  1492. justify-content: flex-start;
  1493. align-items: center;
  1494. >img {
  1495. width: 28rpx;
  1496. height: 30rpx;
  1497. margin-right: 18rpx;
  1498. }
  1499. }
  1500. }
  1501. .evacuation-title-right {
  1502. color: #0183FA;
  1503. font-size: 28rpx;
  1504. line-height: 100rpx;
  1505. }
  1506. }
  1507. /* 一键灭火 */
  1508. .outfire {
  1509. width: 710rpx;
  1510. height: auto;
  1511. background: #FFFFFF;
  1512. border-radius: 20rpx;
  1513. margin: 20rpx 0;
  1514. padding: 26 10rpx;
  1515. box-sizing: border-box;
  1516. display: flex;
  1517. justify-content: space-between;
  1518. align-items: center;
  1519. .outfire_li {
  1520. display: flex;
  1521. justify-content: flex-start;
  1522. padding: 20rpx 10rpx;
  1523. box-sizing: border-box;
  1524. //align-items: center;
  1525. .finish {
  1526. flex: 1;
  1527. }
  1528. >img {
  1529. width: 24rpx;
  1530. height: 30rpx;
  1531. margin-right: 12rpx;
  1532. margin-top: 8rpx;
  1533. }
  1534. .normal {
  1535. font-size: 24rpx;
  1536. font-family: PingFang SC;
  1537. font-weight: 500;
  1538. color: #333333;
  1539. }
  1540. .abnormal {
  1541. font-size: 24rpx;
  1542. font-family: PingFang SC;
  1543. font-weight: 500;
  1544. color: #F11C00;
  1545. }
  1546. }
  1547. .outfire_li:nth-of-type(1) {
  1548. >img {
  1549. width: 30rpx;
  1550. height: 28rpx;
  1551. margin-right: 12rpx;
  1552. }
  1553. }
  1554. .outfire_yes_btn {
  1555. width: 120rpx;
  1556. height: 40rpx;
  1557. font-size: 24rpx;
  1558. font-family: PingFang SC;
  1559. font-weight: 500;
  1560. color: #F21C00;
  1561. line-height: 40rpx;
  1562. border: 1px solid #F21C00;
  1563. border-radius: 8rpx;
  1564. text-align: center;
  1565. margin-left: 54rpx;
  1566. }
  1567. .outfire_no_btn {
  1568. width: 120rpx;
  1569. height: 40rpx;
  1570. font-size: 24rpx;
  1571. font-family: PingFang SC;
  1572. font-weight: 500;
  1573. color: #CCCCCC;
  1574. line-height: 40rpx;
  1575. border: 1px solid #E0E0E0;
  1576. border-radius: 8rpx;
  1577. text-align: center;
  1578. margin-left: 54rpx;
  1579. }
  1580. }
  1581. .evacuation-scroll-box {
  1582. height: 95rpx;
  1583. overflow-x: scroll;
  1584. overflow-y: hidden;
  1585. white-space: nowrap;
  1586. margin: 0 20rpx;
  1587. view {
  1588. line-height: 95rpx;
  1589. font-size: 28rpx;
  1590. display: inline-block;
  1591. margin-right: 45rpx;
  1592. }
  1593. .scroll-box-color {
  1594. color: #0183FA;
  1595. }
  1596. }
  1597. .evacuation-video-box {
  1598. width: 668rpx;
  1599. height: 341rpx;
  1600. margin: 0 auto;
  1601. position: relative;
  1602. video {
  1603. position: absolute;
  1604. top: 0;
  1605. left: 0;
  1606. width: 668rpx;
  1607. height: 341rpx;
  1608. margin: 0 auto;
  1609. }
  1610. .video-a {
  1611. z-index: 100;
  1612. }
  1613. .video-b {
  1614. z-index: 0;
  1615. }
  1616. }
  1617. /* 路线图 */
  1618. .roadmap {
  1619. width: 710rpx;
  1620. height: 464rpx;
  1621. background: #FFFFFF;
  1622. border-radius: 20rpx;
  1623. padding: 20rpx 20rpx 0;
  1624. box-sizing: border-box;
  1625. margin-top: 20rpx;
  1626. .roadmap_t {
  1627. font-size: 30rpx;
  1628. font-family: PingFang SC;
  1629. font-weight: 500;
  1630. color: #333333;
  1631. line-height: 30rpx;
  1632. display: flex;
  1633. .monito_li_r_l {
  1634. flex: 1;
  1635. line-height: 61rpx;
  1636. font-size: 28rpx;
  1637. }
  1638. .monito_li_r_r_button {
  1639. width: 100rpx;
  1640. text-align: center;
  1641. line-height: 61rpx;
  1642. font-size: 28rpx;
  1643. color: #0183FA;
  1644. }
  1645. .monito_li_r {
  1646. width: 380rpx;
  1647. font-size: 24rpx;
  1648. font-family: PingFang SC;
  1649. font-weight: 500;
  1650. color: #0183FA;
  1651. line-height: 80rpx;
  1652. display: flex;
  1653. justify-content: flex-end;
  1654. align-items: center;
  1655. >img {
  1656. width: 9rpx;
  1657. height: 22rpx;
  1658. margin-left: 20rpx;
  1659. }
  1660. .evacuation-title-button-box {
  1661. display: flex;
  1662. overflow: hidden;
  1663. view {
  1664. line-height: 61rpx;
  1665. font-size: 28rpx;
  1666. }
  1667. .colorA {
  1668. color: #0183FA;
  1669. }
  1670. .colorB {
  1671. color: #0183FA;
  1672. }
  1673. img {
  1674. margin: 28rpx 20rpx 0;
  1675. width: 24rpx;
  1676. height: 9rpx;
  1677. }
  1678. }
  1679. }
  1680. }
  1681. .evacuation-map-box {
  1682. width: 668rpx;
  1683. height: 348rpx;
  1684. margin: 0 auto;
  1685. overflow: hidden;
  1686. border: 1rpx solid #E0E0E0;
  1687. margin-top: 20rpx;
  1688. position: relative;
  1689. .emergencyEvacuationBigFullScreen-page {
  1690. // overflow: scroll;
  1691. overflow: hidden;
  1692. position: absolute;
  1693. top: 50%;
  1694. left: 50%;
  1695. .map-max-box {
  1696. position: relative;
  1697. .map-max-for-box {
  1698. position: absolute;
  1699. display: flex;
  1700. flex-direction: column;
  1701. .map-max-for-min-box {
  1702. position: relative;
  1703. .position-box {
  1704. position: absolute;
  1705. }
  1706. .map-for-name-p {
  1707. padding: 0 10rpx;
  1708. height: 20rpx;
  1709. line-height: 20rpx;
  1710. font-size: 14rpx;
  1711. text-align: center;
  1712. color: #333;
  1713. overflow: hidden;
  1714. text-overflow: ellipsis;
  1715. white-space: nowrap;
  1716. }
  1717. .map-for-num-p {
  1718. padding: 0 10rpx;
  1719. height: 20rpx;
  1720. line-height: 20rpx;
  1721. font-size: 14rpx;
  1722. text-align: center;
  1723. color: #333;
  1724. overflow: hidden;
  1725. text-overflow: ellipsis;
  1726. white-space: nowrap;
  1727. }
  1728. }
  1729. }
  1730. .for-map-box {
  1731. border: 2rpx solid #fff;
  1732. background: #CEF2FD;
  1733. }
  1734. .for-map-box-one {
  1735. background: #CEFDD5;
  1736. }
  1737. .room-type-one {
  1738. //选中
  1739. background: rgba(178, 235, 255, 1);
  1740. }
  1741. .room-type-two {
  1742. //报警
  1743. background: rgba(232, 0, 0, 0.4);
  1744. box-shadow: 0 0 10rpx 1rpx #E80000 inset;
  1745. }
  1746. .room-type-three {
  1747. //选中报警
  1748. background: rgba(178, 235, 255, 1);
  1749. box-shadow: 0 0 10rpx 1rpx #E80000 inset;
  1750. }
  1751. }
  1752. }
  1753. }
  1754. }
  1755. .video-max-box {
  1756. width: 710rpx;
  1757. height: 780rpx;
  1758. overflow-y: scroll;
  1759. background: #FFFFFF;
  1760. border-radius: 20rpx;
  1761. padding: 22rpx 30rpx 30rpx;
  1762. box-sizing: border-box;
  1763. margin-top: 20rpx;
  1764. margin-bottom: 120rpx;
  1765. video {
  1766. width: 645rpx;
  1767. height: 355rpx;
  1768. }
  1769. }
  1770. .bottom-button-box {
  1771. position: absolute;
  1772. bottom: 20rpx;
  1773. display: flex;
  1774. width: 670rpx;
  1775. margin: 20rpx;
  1776. view {
  1777. width: 335rpx;
  1778. height: 100rpx;
  1779. line-height: 100rpx;
  1780. text-align: center;
  1781. color: #fff;
  1782. font-size: 28rpx;
  1783. }
  1784. .voice {
  1785. border-top-left-radius: 50rpx;
  1786. border-bottom-left-radius: 50rpx;
  1787. background: #FF9C00;
  1788. }
  1789. .plan {
  1790. background: #21A743;
  1791. }
  1792. .evacuate {
  1793. border-top-right-radius: 50rpx;
  1794. border-bottom-right-radius: 50rpx;
  1795. background: #0183FA;
  1796. }
  1797. }
  1798. }
  1799. .live-button {
  1800. width: 650rpx;
  1801. height: 100rpx;
  1802. line-height: 100rpx;
  1803. text-align: center;
  1804. font-size: 28rpx;
  1805. margin: 50rpx auto 0;
  1806. border-radius: 20rpx;
  1807. }
  1808. .live-color-a {
  1809. color: #fff;
  1810. background: #FF8686;
  1811. }
  1812. .live-color-b {
  1813. color: #fff;
  1814. background: #25C95B;
  1815. }
  1816. /* 语音广播 */
  1817. .shade-max-big-box {
  1818. height: 100%;
  1819. width: 100%;
  1820. position: fixed;
  1821. display: flex;
  1822. flex-direction: column;
  1823. z-index: 10;
  1824. background: rgba(0, 0, 0, 0.2);
  1825. .null-box {
  1826. flex: 1;
  1827. }
  1828. /* 语音广播-执行疏散 */
  1829. .broadcast {
  1830. width: 100%;
  1831. // height: 532rpx;
  1832. background: #FFFFFF;
  1833. border-top-left-radius: 20rpx;
  1834. border-top-right-radius: 20rpx;
  1835. padding: 22rpx 30rpx 30rpx;
  1836. box-sizing: border-box;
  1837. margin-top: 20rpx;
  1838. .broadcast_t {
  1839. font-size: 30rpx;
  1840. font-family: PingFang SC;
  1841. font-weight: 500;
  1842. color: #333333;
  1843. line-height: 30rpx;
  1844. >label {
  1845. font-size: 24rpx;
  1846. font-family: PingFang SC;
  1847. font-weight: 500;
  1848. color: #999999;
  1849. line-height: 30rpx;
  1850. margin-left: 16rpx;
  1851. }
  1852. }
  1853. .trumpet-max-box {
  1854. display: flex;
  1855. justify-content: flex-start;
  1856. margin-top: 22rpx;
  1857. flex-wrap: wrap;
  1858. .trumpet-for-box {
  1859. display: inline-block;
  1860. width: auto;
  1861. height: 60rpx;
  1862. line-height: 60rpx;
  1863. font-size: 24rpx;
  1864. text-align: center;
  1865. cursor: pointer;
  1866. overflow: hidden;
  1867. border: 1rpx solid #E0E0E0;
  1868. border-radius: 10rpx;
  1869. color: #E0E0E0;
  1870. display: flex;
  1871. justify-content: center;
  1872. margin-right: 20rpx;
  1873. margin-bottom: 10rpx;
  1874. padding: 0 12rpx;
  1875. box-sizing: border-box;
  1876. >img {
  1877. width: 36rpx;
  1878. height: 34rpx;
  1879. margin: 12rpx 20rpx 0 25rpx;
  1880. }
  1881. }
  1882. .trumpet-color-a {
  1883. border: 1px solid #0183FA;
  1884. color: #0183FA;
  1885. }
  1886. .trumpet-color-b {
  1887. border: 1px solid #CCCCCC;
  1888. color: #999;
  1889. }
  1890. }
  1891. .no-long-press{
  1892. // -webkit-touch-callout: none; /* iOS Safari */
  1893. // -webkit-user-select: none; /* Chrome, Safari 3 */
  1894. // -khtml-user-select: none; /* Safari 2 */
  1895. // -moz-user-select: none; /* Firefox */
  1896. // -ms-user-select: none; /* Internet Explorer/Edge */
  1897. // user-select: none; /* Non-prefixed version, supported in most modern browsers */
  1898. }
  1899. .broadcast_m {
  1900. width: 100%;
  1901. margin-bottom: 80rpx;
  1902. .broadcast_m_t {
  1903. width: 142rpx;
  1904. height: 142rpx;
  1905. margin: 30rpx 0 0 258rpx;
  1906. position: relative;
  1907. font-size: 24rpx;
  1908. font-family: PingFang SC;
  1909. font-weight: 500;
  1910. line-height: 170rpx;
  1911. text-align: center;
  1912. >img {
  1913. width: 142rpx;
  1914. height: 142rpx;
  1915. position: absolute;
  1916. }
  1917. >label {
  1918. width: 100%;
  1919. font-size: 24rpx;
  1920. font-family: PingFang SC;
  1921. font-weight: 500;
  1922. color: #0183FA;
  1923. line-height: 24rpx;
  1924. display: inline-block;
  1925. text-align: center;
  1926. position: absolute;
  1927. top: 76rpx;
  1928. }
  1929. /* 按下 */
  1930. .press_color {
  1931. color: #FFFFFF;
  1932. }
  1933. /* 松开 */
  1934. .slip_color {
  1935. color: #0183FA;
  1936. }
  1937. }
  1938. .broadcast_m_b {
  1939. font-size: 24rpx;
  1940. font-family: PingFang SC;
  1941. font-weight: 500;
  1942. color: #999999;
  1943. line-height: 24rpx;
  1944. text-align: center;
  1945. margin-top: 14rpx;
  1946. }
  1947. }
  1948. /* 疏散按钮 */
  1949. .evacuation-button-box {
  1950. width: 650rpx;
  1951. height: 100rpx;
  1952. background: #0183FA;
  1953. color: #fff;
  1954. text-align center;
  1955. line-height: 100rpx;
  1956. font-size: 28rpx;
  1957. margin: 88rpx auto 0;
  1958. border-radius: 20rpx;
  1959. }
  1960. }
  1961. }
  1962. }
  1963. .setUpEvacuation-bottom-button {
  1964. width: 650rpx;
  1965. height: 100rpx;
  1966. background: #0183FA;
  1967. color: #fff;
  1968. text-align: center;
  1969. line-height: 100rpx;
  1970. font-size: 28rpx;
  1971. margin: 50rpx auto;
  1972. border-radius: 20rpx;
  1973. }
  1974. .device-type {
  1975. margin-top:20rpx;
  1976. border-radius:20rpx;
  1977. background: #fff;
  1978. padding: 24rpx 20rpx;
  1979. box-sizing: border-box;
  1980. display: flex;
  1981. justify-content: flex-start;
  1982. flex-wrap: wrap;
  1983. >view {
  1984. //width: 356rpx;
  1985. height: 60rpx;
  1986. display: flex;
  1987. justify-content: flex-start;
  1988. align-items: center;
  1989. padding-left: 10rpx;
  1990. padding-right: 10rpx;
  1991. box-sizing: border-box;
  1992. >img:nth-of-type(1) {
  1993. width: 42rpx;
  1994. height: 42rpx;
  1995. margin-right: 12rpx;
  1996. }
  1997. >view {
  1998. font-family: PingFang SC;
  1999. font-weight: 500;
  2000. font-size: 30rpx;
  2001. color: #222222;
  2002. line-height: 60rpx;
  2003. width: 560rpx;
  2004. }
  2005. >img:nth-of-type(2) {
  2006. width: 24rpx;
  2007. height: 22rpx;
  2008. }
  2009. }
  2010. >view:nth-child(2n) {
  2011. border-right: none;
  2012. padding-left: 20rpx;
  2013. box-sizing: border-box;
  2014. }
  2015. >view:nth-last-child(1) {
  2016. border-bottom: none;
  2017. }
  2018. >view:nth-last-child(2) {
  2019. border-bottom: none;
  2020. }
  2021. }
  2022. .for-map-box-two {
  2023. background: url($imagesUrl+'manage/icon_yjtd.png') center center no-repeat #006400;
  2024. background-size: 60rpx 60rpx;
  2025. }
  2026. .for-map-box-two-check {
  2027. background: url($imagesUrl+'manage/icon_yjtd.png') center center no-repeat rgba(50, 205, 50, 1);
  2028. background-size: 80rpx 80rpx;
  2029. }
  2030. .center-move-door-p-t {
  2031. background: url($imagesUrl+'manage/icon_sysbjt_m.png') !important;
  2032. background-size: 100% !important;
  2033. transform: rotate(180deg);
  2034. }
  2035. .center-move-door-p-b {
  2036. background: url($imagesUrl+'manage/icon_sysbjt_m.png') !important;
  2037. background-size: 100% !important;
  2038. }
  2039. .center-move-door-p-l {
  2040. background: url($imagesUrl+'manage/icon_sysbjt_m.png') !important;
  2041. background-size: 100% !important;
  2042. transform: rotate(90deg);
  2043. }
  2044. .center-move-door-p-r {
  2045. background: url($imagesUrl+'manage/icon_sysbjt_m.png') !important;
  2046. background-size: 100% !important;
  2047. transform: rotateZ(270deg);
  2048. }
  2049. .lightTopOn {
  2050. background: url($imagesUrl+'manage/icon_sjt.png');
  2051. background-size: 100%;
  2052. }
  2053. .lightTopOff {
  2054. background: url($imagesUrl+'manage/icon_shang_hs.png');
  2055. background-size: 100%;
  2056. }
  2057. .lightBottomOn {
  2058. background: url($imagesUrl+'manage/icon_xjt.png');
  2059. background-size: 100%;
  2060. }
  2061. .lightBottomOff {
  2062. background: url($imagesUrl+'manage/icon_xia_hs.png');
  2063. background-size: 100%;
  2064. }
  2065. .lightLeftOn {
  2066. background: url($imagesUrl+'manage/icon_zuo.png');
  2067. background-size: 100%;
  2068. }
  2069. .lightLeftOff {
  2070. background: url($imagesUrl+'manage/icon_zou_hs.png');
  2071. background-size: 100%;
  2072. }
  2073. .lightRightOn {
  2074. background: url($imagesUrl+'manage/icon_yuo.png');
  2075. background-size: 100%;
  2076. }
  2077. .lightRightOff {
  2078. background: url($imagesUrl+'manage/icon_you_hs.png');
  2079. background-size: 100%;
  2080. }
  2081. .broadcast_m_t_back_a {
  2082. background: url($imagesUrl+'commonality/icon_sskz_skfs_1.png');
  2083. color: #FFFFFF;
  2084. background-size: 100%;
  2085. }
  2086. .broadcast_m_t_back_b {
  2087. background: url($imagesUrl+'commonality/icon_sskz_azsh_1.png');
  2088. color: #0183FA;
  2089. background-size: 100%;
  2090. }
  2091. }
  2092. </style>