index.tsx 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115
  1. import {
  2. defineComponent,
  3. reactive,
  4. PropType,
  5. onMounted,
  6. watchEffect,
  7. watch,
  8. computed,
  9. onUnmounted,
  10. } from 'vue';
  11. import {
  12. ResourceItemDetail,
  13. getResourceItem,
  14. ResourceItemDetailResponse,
  15. } from '@/api/resource';
  16. import { useRoute, useRouter } from 'vue-router';
  17. import isString from 'lodash/isString';
  18. import useMarkerStore, { MarkerType } from '@/store/useMarkerStore';
  19. import MapView from '../MapView';
  20. import { useDaHuaStore,useMainStore } from '@/store';
  21. import emitter from '@/utils/mitt';
  22. /** @ts-ignore */
  23. import icon_map_yjcl from '@/assets/icons/home/yjcl.svg';
  24. /** @ts-ignore */
  25. import icon_map_yjsj from '@/assets/icons/home/yjsj.svg';
  26. /** @ts-ignore */
  27. import icon_map_yjdw from '@/assets/icons/home/yjdw.svg';
  28. /** @ts-ignore */
  29. import icon_map_yjdw_w from '@/assets/icons/home/icon_map_yjdw_w.svg';
  30. /** @ts-ignore */
  31. import icon_map_yjck from '@/assets/icons/home/yjck.svg';
  32. /** @ts-ignore */
  33. import icon_map_yjck_w from '@/assets/icons/home/icon_map_yjck_w.svg';
  34. /** @ts-ignore */
  35. import icon_map_spjk from '@/assets/icons/home/spjk.svg';
  36. /** @ts-ignore */
  37. import icon_map_spjk_offline from '@/assets/icons/home/spjkoffline.svg';
  38. /** @ts-ignore */
  39. import icon_map_dcz from '@/assets/icons/home/icon_map_dcz.svg';
  40. /** @ts-ignore */
  41. import icon_map_dpf from '@/assets/icons/home/dpf.svg';
  42. /** @ts-ignore */
  43. import icon_map_dbsb from '@/assets/icons/home/dbsb.svg';
  44. // @ts-ignore
  45. import icon_map_traffic from '@/assets/icons/detail/source2@2x.png';
  46. import './index.scss';
  47. import {
  48. GET_INCIDENT_DIALOG_HTML,
  49. GET_TEAM_DIALOG_HTML,
  50. GET_VEHICLES_DIALOG_HTML,
  51. GET_VIDEO_DIALOG_HTML,
  52. GET_WAREHOUSE_DIALOG_HTML,
  53. GET_SINGLE_DEVICE_DIALOG_HTML,
  54. renderElement,
  55. } from './dialog';
  56. import { IncidentItemDetail } from '@/api/incident';
  57. import { useIncidentStore } from '@/store';
  58. import Popup from '../Popup';
  59. import { ElMessage } from 'element-plus';
  60. import { isEmpty, xor } from 'lodash';
  61. import clsx from 'clsx';
  62. import { SingleDeviceItem } from '@/api/resource';
  63. const MARKER_MAP_TYPES = [
  64. // '待派发事件',
  65. // '待处置事件',
  66. '路况信息',
  67. '视频监控',
  68. '应急车辆',
  69. '应急队伍',
  70. '应急仓库',
  71. '应急事件',
  72. '单兵',
  73. ] as const;
  74. export type MarkerMapType = typeof MARKER_MAP_TYPES[number];
  75. interface State {
  76. map: any;
  77. types: MarkerMapType[];
  78. trafficLayerIds: any[];
  79. timer?: NodeJS.Timer | null;
  80. trafficStatus: boolean;
  81. markers: MarkerType[];
  82. positions: string[];
  83. hasTypes: string[];
  84. // theSocket: null;
  85. }
  86. interface ActionType {
  87. type: MarkerMapType;
  88. hasActioned: boolean;
  89. action: Function;
  90. remove: Function;
  91. }
  92. // locationType + resourceType
  93. const RESOURCE_ICON_MAP = {
  94. '11': icon_map_yjck_w, // 水上 仓库
  95. '21': icon_map_yjck, // 陆上 仓库
  96. '12': icon_map_yjdw_w, // 水上 队伍
  97. '22': icon_map_yjdw, // 陆上 队伍
  98. '13': icon_map_yjcl, // 水上 车辆
  99. '23': icon_map_yjcl, // 陆上 车辆
  100. };
  101. const getResourceIcon = (locationType: string, resourceType: string) => {
  102. // @ts-ignore
  103. return RESOURCE_ICON_MAP[locationType + resourceType] || '';
  104. };
  105. // 路况信息刷新间隔
  106. const REFRESH_TRAFFIC_TIME = 60000;
  107. // let theSocket = null;
  108. // let vPlayArea =null;
  109. const getIncidentImage = (status: MarkerType['status']) =>
  110. status?.toString() === '1'
  111. ? icon_map_yjsj
  112. : status?.toString() === '2'
  113. ? icon_map_dpf
  114. : status?.toString() === '3'
  115. ? icon_map_dcz
  116. : icon_map_yjsj;
  117. export default defineComponent({
  118. name: 'MarkerMap',
  119. props: {
  120. adrsMapTypes: {
  121. type: Array as PropType<string[]>,
  122. default: MARKER_MAP_TYPES,
  123. },
  124. marker: Object as PropType<IncidentItemDetail | undefined | null>,
  125. readonly: Boolean,
  126. },
  127. setup(props, ctx) {
  128. const state = reactive<State>({
  129. map: null,
  130. types: [],
  131. trafficLayerIds: [],
  132. timer: undefined,
  133. trafficStatus: false,
  134. markers: [],
  135. positions: [],
  136. hasTypes: [],
  137. // theSocket:null
  138. });
  139. const store = useMarkerStore();
  140. const mainstore = useMainStore();
  141. const incidentStore = useIncidentStore();
  142. const daHuaStore = useDaHuaStore();
  143. const router = useRouter();
  144. const route = useRoute();
  145. // const theSocket = null;
  146. const adrsMapTypes = computed(() =>
  147. props.adrsMapTypes.map((i) => ({
  148. name: i,
  149. icon: ((name) => {
  150. switch(name)
  151. {
  152. case "路况信息": return icon_map_traffic;
  153. case "应急事件": return icon_map_dpf;
  154. case "视频监控": return icon_map_spjk;
  155. case "应急车辆": return icon_map_yjcl;
  156. case "应急队伍": return icon_map_yjdw;
  157. case "应急仓库": return icon_map_yjck;
  158. case "单兵": return icon_map_dbsb;
  159. }
  160. })(i),
  161. disabled: route.query.id && i === '应急事件',
  162. })),
  163. );
  164. const actionTypes = computed<ActionType[]>(() => [
  165. {
  166. type: '路况信息',
  167. hasActioned: state.trafficStatus,
  168. action: toggleControlTraffic,
  169. remove: toggleControlTraffic,
  170. },
  171. {
  172. type: '应急事件',
  173. hasActioned: state.hasTypes.includes('应急事件'),
  174. action: () =>
  175. handleAddMarkers('应急事件', store.incident, icon_map_dpf),
  176. remove: () => handleRemoveMarkers('应急事件', store.incident),
  177. },
  178. {
  179. type: '视频监控',
  180. hasActioned: state.hasTypes.includes('视频监控'),
  181. action: () =>
  182. // console.log(store.videoSurveillance);
  183. handleAddMarkers('视频监控', store.videoSurveillance, icon_map_spjk),
  184. remove: () => handleRemoveMarkers('视频监控', store.videoSurveillance),
  185. },
  186. {
  187. type: '应急车辆',
  188. hasActioned: state.hasTypes.includes('应急车辆'),
  189. action: () =>
  190. handleAddMarkers('应急车辆', store.emergencyVehicles, icon_map_yjcl),
  191. remove: () => handleRemoveMarkers('应急车辆', store.emergencyVehicles),
  192. },
  193. {
  194. type: '应急队伍',
  195. hasActioned: state.hasTypes.includes('应急队伍'),
  196. action: () =>
  197. handleAddMarkers('应急队伍', store.emergencyTeam, icon_map_yjdw),
  198. remove: () => handleRemoveMarkers('应急队伍', store.emergencyTeam),
  199. },
  200. {
  201. type: '应急仓库',
  202. hasActioned: state.hasTypes.includes('应急仓库'),
  203. action: () =>
  204. handleAddMarkers('应急仓库', store.emergencyWarehouse, icon_map_yjck),
  205. remove: () => handleRemoveMarkers('应急仓库', store.emergencyWarehouse),
  206. },
  207. {
  208. type: '单兵',
  209. hasActioned: state.hasTypes.includes('单兵'),
  210. action: () =>
  211. handleAddMarkers('单兵', store.singleDevice, icon_map_dbsb),
  212. remove: () => handleRemoveMarkers('单兵', store.singleDevice),
  213. },
  214. ]);
  215. const getMarkerPopupHTML = (type: MarkerMapType, marker: MarkerType) => {
  216. switch (type) {
  217. case '应急事件':
  218. // case '待派发事件':
  219. // case '预警事件':
  220. default:
  221. return GET_INCIDENT_DIALOG_HTML(marker, async () => {
  222. marker.id && (await incidentStore.getIncidentItem(marker.id));
  223. await router.push(`/incidentDetail?id=${marker?.id}`);
  224. handleSetDetailMarker(marker);
  225. store.currentIncident = marker;
  226. });
  227. case '单兵': {
  228. var callback = () => {
  229. // console.log(marker['deviceCode']);
  230. // console.log(marker['userId']);
  231. // daHuaStore.DAHUAUserObj(marker["userId"]).then(deviceUser=>{
  232. // console.log(deviceUser);
  233. // let memberObj = {
  234. // userName:deviceUser.userName,
  235. // userId:deviceUser.userCode,
  236. // region:deviceUser.paasId,
  237. // type:'single',
  238. // // speak:'true',
  239. // number:deviceUser.userPhone,
  240. // deviceId:marker["deviceCode"],
  241. // channelId:marker["channelId"],
  242. // }
  243. // let meetObj = JSON.parse(localStorage.getItem('meeting'));
  244. // let memberList = [];
  245. // memberList.push(meetObj.member==null||meetObj.member==undefined?"":meetObj.member[0]);
  246. // memberList.push(memberObj);
  247. // meetObj.member = memberList
  248. // console.log(meetObj);
  249. // daHuaStore.DAHUAMeetingMember(meetObj).then(data=>{
  250. // // console.log(11111111)
  251. // daHuaStore.DAHUAMeetingUser(meetObj.meetId);
  252. // daHuaStore.DAHUAUserInfo().then(u => {
  253. // console.log(u,'+++++++');
  254. // initSocket(u.userCode,memberObj);
  255. // })
  256. // })
  257. // console.log(memberObj);
  258. // meetObj.mebmber.push(memberObj);
  259. // mainstore.videoisshow = true;
  260. mainstore.videoisshow = true;
  261. // // try {
  262. // daHuaStore.DAHUAUserObj(marker["userId"]).then(deviceUser=>{
  263. mainstore.videotitle = marker["userName"] + "";
  264. // });
  265. const userid = marker['userId'];
  266. const dievicecode = marker['deviceCode']+"";
  267. const channelid = marker['channelId']+"";
  268. async function cremetting(){
  269. await window.metting.getLocalUserInfo();
  270. const res = await window.metting.queryUser(userid);
  271. window.metting.localUserInfo.name = "danbing_Meeting";
  272. await window.metting.creatMeeting();
  273. await window.metting.startInvite({
  274. userName: res.userName,
  275. userId: res.userCode,
  276. region: res.paasId,
  277. type: "single",
  278. // speak:'true',
  279. number: res.userPhone,
  280. deviceId: dievicecode,
  281. channelId: channelid,
  282. });
  283. }
  284. if(window.metting){
  285. const meeting = window.metting;
  286. meeting.settargetId("vPlayArea");
  287. meeting.playVideo({
  288. type: 'single',
  289. deviceId: marker['deviceCode'],
  290. channelId: channelid,
  291. });
  292. cremetting();
  293. setTimeout(() => {
  294. try{
  295. if(window.vPlayArea){
  296. window.vPlayArea.resize();
  297. window.vPlayArea.dragResize(0,0,0,0)
  298. }
  299. }catch(E){
  300. }
  301. }, 500);
  302. }else{
  303. const meeting = new Meeting();
  304. if(window.theSocket){
  305. meeting.settargetId("vPlayArea");
  306. meeting.playVideo({
  307. type: 'single',
  308. deviceId: marker['deviceCode'],
  309. channelId: channelid,
  310. });
  311. window.metting = meeting;
  312. setTimeout(() => {
  313. try{
  314. if(window.vPlayArea){
  315. window.vPlayArea.resize();
  316. window.vPlayArea.dragResize(0,0,0,0)
  317. }
  318. }catch(E){
  319. }
  320. }, 500);
  321. }else{
  322. meeting.openClient(() => {
  323. meeting.settargetId("vPlayArea");
  324. meeting.playVideo({
  325. type: 'single',
  326. deviceId: marker['deviceCode'],
  327. channelId: channelid,
  328. });
  329. window.metting = meeting;
  330. cremetting();
  331. setTimeout(() => {
  332. try{
  333. if(window.vPlayArea){
  334. window.vPlayArea.resize();
  335. window.vPlayArea.dragResize(0,0,0,0)
  336. }
  337. }catch(E){
  338. }
  339. }, 1000);
  340. });
  341. }
  342. }
  343. // mainstore.videohandle = meeting;
  344. // });
  345. // const DAHUA = document.getElementById('DAHUA') as HTMLIFrameElement;
  346. // DAHUA?.contentWindow?.postMessage(
  347. // {
  348. // key: 'danbing',
  349. // value: marker['userId'],
  350. // deviceId: marker['deviceCode'],
  351. // channelId: marker['channelId'],
  352. // },
  353. // '*',
  354. // );
  355. // daHuaStore.dahuaUserVisible = true;
  356. // console.log(daHuaStore.deviceUser);
  357. };
  358. return GET_SINGLE_DEVICE_DIALOG_HTML(
  359. marker as SingleDeviceItem,
  360. callback,
  361. );
  362. }
  363. case '应急仓库':
  364. return GET_WAREHOUSE_DIALOG_HTML(marker);
  365. case '应急车辆':
  366. return GET_VEHICLES_DIALOG_HTML(marker);
  367. case '应急队伍':
  368. return GET_TEAM_DIALOG_HTML(marker);
  369. case '视频监控':
  370. return GET_VIDEO_DIALOG_HTML(marker, (type=1) => {
  371. if (marker['status'] == 1) {
  372. // mainstore.videourl =
  373. // (import.meta.env.VITE_DH_SERVER as string) +
  374. // '/videoplay.html?channelId=' +
  375. // marker['deviceCode'];
  376. const channelid = marker['channelId']+"";
  377. if(type==1){
  378. mainstore.videoisshow = true;
  379. mainstore.videotitle = marker['name'] + "";
  380. if(window.metting){
  381. const meeting = window.metting;
  382. meeting.settargetId("vPlayArea");
  383. meeting.playVideo({
  384. type: 'single',
  385. deviceId: marker['deviceCode'],
  386. channelId: channelid,
  387. });
  388. setTimeout(() => {
  389. try{
  390. if(window.vPlayArea){
  391. window.vPlayArea.resize();
  392. window.vPlayArea.dragResize(0,0,0,0)
  393. }
  394. }catch(E){
  395. }
  396. }, 500);
  397. }else{
  398. const meeting = new Meeting();
  399. if(window.theSocket){
  400. meeting.settargetId("vPlayArea");
  401. meeting.playVideo({
  402. type: 'single',
  403. deviceId: marker['deviceCode'],
  404. channelId: channelid,
  405. });
  406. window.metting = meeting;
  407. setTimeout(() => {
  408. try{
  409. if(window.vPlayArea){
  410. window.vPlayArea.resize();
  411. window.vPlayArea.dragResize(0,0,0,0)
  412. }
  413. }catch(E){
  414. }
  415. }, 500);
  416. }else{
  417. meeting.openClient(() => {
  418. meeting.settargetId("vPlayArea");
  419. meeting.playVideo({
  420. type: 'single',
  421. deviceId: marker['deviceCode'],
  422. channelId: channelid,
  423. });
  424. window.metting = meeting;
  425. setTimeout(() => {
  426. try{
  427. if(window.vPlayArea){
  428. window.vPlayArea.resize();
  429. window.vPlayArea.dragResize(0,0,0,0)
  430. }
  431. }catch(E){
  432. }
  433. }, 1000);
  434. });
  435. }
  436. }
  437. }
  438. if(type==2){
  439. window.indexp = (window.indexp == 1?2:1);
  440. const meeting = new Meeting();
  441. if(window.theSocket){
  442. meeting.settargetId("relvideo"+window.indexp);
  443. meeting.playVideo({
  444. type: 'single',
  445. deviceId: marker['deviceCode'],
  446. channelId: channelid,
  447. });
  448. }else{
  449. meeting.openClient(() => {
  450. meeting.settargetId("relvideo"+window.indexp);
  451. meeting.playVideo({
  452. type: 'single',
  453. deviceId: marker['deviceCode'],
  454. channelId: channelid,
  455. });
  456. });
  457. }
  458. }
  459. // // try {
  460. // const meeting = new Meeting();
  461. // meeting.closeVideo();
  462. // meeting.openClient(() => {
  463. // meeting.settargetId("");
  464. // meeting.playVideo({
  465. // type: 'single',
  466. // deviceId: marker['deviceCode'],
  467. // channelId: channelid,
  468. // });
  469. // });
  470. // mainstore.videohandle = meeting;
  471. // } catch (E) { }
  472. // const DAHUA = document.getElementById('DAHUA') as HTMLIFrameElement;
  473. // DAHUA?.contentWindow?.postMessage(
  474. // {
  475. // key: 'video',
  476. // value: marker['userId'],
  477. // deviceId: marker['deviceCode'],
  478. // channelId: marker['channelId'],
  479. // },
  480. // '*',
  481. // );
  482. // daHuaStore.dahuaUserVisible = true;
  483. }else{
  484. ElMessage.warning('设备离线,请联系大华相关人员');
  485. }
  486. });
  487. }
  488. };
  489. const videoplay = (item: { type: string; userId: any; channelId: any }) => {
  490. // console.log('播放视频');
  491. // console.log(item);
  492. if (!window.theSocket.websocket) {
  493. ElMessage.warning('请先打开视频插件');
  494. return;
  495. }
  496. if (item.type == 'client') {
  497. window.slectOptionmini(item.userId).then((arr: any) => {
  498. if (arr) {
  499. window.vPlayArea.openAppVideo(arr);
  500. }
  501. });
  502. } else if (item.type == 'single') {
  503. //播放单兵视频
  504. pullFlow(item.channelId);
  505. } else if (item.type == 'vehicle') {
  506. //播放车载视频
  507. pullFlow(item.channelId);
  508. } else if (item.type == 'uav_dev') {
  509. //播放无人机视频
  510. pullFlow(item.channelId);
  511. }
  512. };
  513. const pullFlow = (channelId: any) => {
  514. channelId &&
  515. window.vPlayArea &&
  516. window.vPlayArea.realTimeVideo([{ channelId }]);
  517. };
  518. const initSocket = (
  519. userCode: string,
  520. memberObj: {
  521. userName?: any;
  522. userId: any;
  523. region?: any;
  524. type: string;
  525. number?: any;
  526. deviceId?: any;
  527. channelId: any;
  528. },
  529. ) => {
  530. const self = this;
  531. // console.log(userCode);
  532. localStorage.setItem('userId', userCode);
  533. //初始websocket实例,保存在window中方便调用。一个浏览器tab页面只能初始化一次。所有的控件窗口,通过该websocket实例去生成不同的窗口实例,不同的控件窗口通过自己的窗口实例去调用初始化、关闭、隐藏等
  534. window.theSocket = new window.InitWebSocketClass(
  535. userCode,
  536. localStorage.getItem('DAHUA_token'),
  537. {
  538. //客户端登陆成功通知;
  539. loginSuccess: (v: any) => {
  540. // console.log(2222222222222222);
  541. console.log('loginSuccess-->', v);
  542. initWnd();
  543. },
  544. //客户端窗口被拉起通知
  545. onCreateVideoSuccess: (v: any) => {
  546. console.log('客户端onCreateVideoSuccess-----', v);
  547. },
  548. //重点:统一分发客户端ws消息;vue 可以统一用$bus分发.第三方消息分发自定
  549. onSocketBackInfos: (data: {
  550. method: string;
  551. params: { result: number; handleName: string };
  552. }) => {
  553. //视频窗口创建成功通知
  554. if (
  555. data &&
  556. data.method === 'createVideoDialogReuslt' &&
  557. data.params.result === 0
  558. ) {
  559. if (data.params.handleName === '#vPlayArea') {
  560. //客户端窗口创建好后,界面显示窗口;
  561. window.vPlayArea.resize();
  562. ElMessage.warning('视频窗口创建成功!');
  563. videoplay(memberObj);
  564. }
  565. }
  566. },
  567. },
  568. );
  569. // console.log(theSocket);
  570. //socket实例初始化websocket回调方法;
  571. window.theSocket
  572. .initWebSocket()
  573. .then((v: any) => {
  574. if (v) {
  575. ElMessage.warning('视频插件登陆完成!');
  576. }
  577. })
  578. .catch(() => {
  579. ElMessage.warning('若要观看实时视频,请先安装视频插件');
  580. });
  581. };
  582. const initWnd = () => {
  583. // console.log(1111);
  584. //左边窗口类型参数 分割 2行2列
  585. const typeObj = {
  586. rows: 2,
  587. cols: 2,
  588. wndSpaceing: 10,
  589. embedVideoMode: true,
  590. playerCtrlBarEnable: false,
  591. displayMode: 0,
  592. playMode: 0,
  593. playParams: {},
  594. };
  595. //左边窗口实例
  596. window.vPlayArea = new window.VideoPlay(
  597. '#vPlayArea',
  598. window.theSocket.websocket, //一个浏览器tab页面公用一个
  599. window.theSocket.socketCode, //一个浏览器tab页面公用一个
  600. typeObj,
  601. );
  602. //左边窗口初始化
  603. window.vPlayArea.init();
  604. };
  605. const updateTrafficSource = () => {
  606. if (state.map.getSource('Traffic')) {
  607. state.map.removeSource('Traffic');
  608. }
  609. state.map.addSource('Traffic', {
  610. type: 'vector',
  611. traffic: true,
  612. tiles: [
  613. 'mineserver://data/dynamic-traffic/ertic?servicetype=0&z={z}&x={x}&y={y}',
  614. ],
  615. });
  616. };
  617. const updateTrafficLayerVisibility = (v: 'none' | 'visible') => {
  618. state.trafficLayerIds.forEach(function (id) {
  619. if (state.map?.getLayer(id)) {
  620. state.map?.setLayoutProperty(id, 'visibility', v);
  621. }
  622. });
  623. };
  624. const toggleControlTraffic = () => {
  625. if (state.trafficStatus) {
  626. state.trafficStatus = false;
  627. if (state.timer) {
  628. clearInterval(state.timer);
  629. state.timer = null;
  630. }
  631. updateTrafficLayerVisibility('none');
  632. } else {
  633. state.trafficStatus = true;
  634. if (state.timer) {
  635. clearInterval(state.timer);
  636. state.timer = null;
  637. }
  638. updateTrafficSource();
  639. state.timer = setInterval(function () {
  640. updateTrafficSource();
  641. }, REFRESH_TRAFFIC_TIME);
  642. updateTrafficLayerVisibility('visible');
  643. }
  644. };
  645. const handleAddMarkers = (
  646. type: MarkerMapType,
  647. markers: State['markers'],
  648. image: any,
  649. ) => {
  650. // console.log(state.markers);
  651. state.markers.push(
  652. ...markers.map((i) => {
  653. var nextImage1 =
  654. type === '应急事件'
  655. ? getIncidentImage(i?.status)
  656. : i.locationType && i.resourceType
  657. ? getResourceIcon(
  658. i.locationType.toString(),
  659. i.resourceType.toString(),
  660. )
  661. : image;
  662. if (type == "视频监控") {
  663. if (i.isOnline == false) {
  664. nextImage1 = icon_map_spjk_offline;
  665. }
  666. }
  667. const nextImage = nextImage1;
  668. const popup = new window.minemap.Popup({
  669. anchor: 'left',
  670. closeOnClick: true,
  671. closeButton: false,
  672. offset: [10, 25],
  673. maxWidth: 'max-content',
  674. // autoPan: true,
  675. }).setDOMContent(getMarkerPopupHTML(type, i));
  676. popup.on('open', function () {
  677. getResourceItem(i.id ?? 0).then(
  678. (res: ResourceItemDetailResponse) => {
  679. var element = document.getElementById('tbl-' + i.id);
  680. var header = [
  681. '序号',
  682. '名称',
  683. '型号',
  684. '规格',
  685. '仓储数量',
  686. '可用数量',
  687. '单位',
  688. ];
  689. try {
  690. element.innerHTML = ` <tr>
  691. ${header.map((i) => '<th>' + i + '</th>').join('')}
  692. </tr>${res.data.resourceDetailList?.map((itemc,index) => {
  693. return `<tr><td>${index + 1}</td><td>${itemc.name ?? '-'}</td><td>${
  694. itemc.model ?? '-'
  695. }</td><td>${itemc.size ?? '-'}</td><td>${itemc.num ?? '-'}</td><td>${
  696. itemc.availableNum ?? '-'
  697. }</td><td>${itemc.unit ?? '-'}</td></tr>`;
  698. }).join("")}`;
  699. } catch (error) {}
  700. },
  701. );
  702. });
  703. return {
  704. locations: i.locations,
  705. popup,
  706. marker:
  707. i.locations &&
  708. new window.minemap.Marker(renderElement(nextImage), {
  709. offset: [-25, -25],
  710. })
  711. .setLngLat({
  712. lng: ((i) => { var ii = parseFloat(i.locations?.split(',')[0] ?? "0"); return ii; })(i),
  713. lat: ((i) => { var ii = parseFloat(i.locations?.split(',')[1] ?? "0"); return ii>90?89:ii<-90?-89:ii; })(i) ,
  714. })
  715. .setPopup(popup)
  716. .addTo(state.map),
  717. };
  718. }),
  719. );
  720. state.positions.push(...markers.map((i) => i.locations).filter(isString));
  721. handleFitBounds();
  722. };
  723. const handleFitBounds = () => {
  724. if (state.positions.length === 0) {
  725. return;
  726. }
  727. const locations = state.positions.map((i) => i.split(',').map(Number));
  728. const leftTop = locations.reduce((carry, next) => {
  729. if (carry.length === 0) return next;
  730. var x = Math.min(carry[0], next[0]);
  731. var y = Math.max(carry[1], next[1]);
  732. return [x<118?118:x, y>35?35:y<30?30:y];
  733. }, []);
  734. console.log(leftTop)
  735. const rightBottom = locations.reduce((carry, next) => {
  736. if (carry.length === 0) return next;
  737. return [Math.max(carry[0], next[0]), Math.min(carry[1], next[1])];
  738. }, []);
  739. const leftTopBounds: number[][] = new window.minemap.LngLat(...leftTop)
  740. .toBounds(5000)
  741. .toArray();
  742. const rightBottomBounds: number[][] = new window.minemap.LngLat(
  743. ...rightBottom,
  744. )
  745. .toBounds(5000)
  746. .toArray();
  747. state.map.fitBounds([
  748. rightBottomBounds.reduce((carry, next) => {
  749. if (carry.length === 0) return next;
  750. return [Math.max(carry[0], next[0]), Math.min(carry[1], next[1])];
  751. }, []),
  752. leftTopBounds.reduce((carry, next) => {
  753. if (carry.length === 0) return next;
  754. return [Math.min(carry[0], next[0]), Math.max(carry[1], next[1])];
  755. }, []),
  756. ]);
  757. };
  758. const handleRemoveMarkers = (
  759. type: MarkerMapType,
  760. markers: State['markers'],
  761. ) => {
  762. state.hasTypes = state.hasTypes.filter((t) => t !== type);
  763. const locations = markers.map((i) => i.locations);
  764. state.markers.forEach((m) => {
  765. if (locations.includes(m.locations)) {
  766. m.marker?.remove();
  767. m.popup?.remove();
  768. m.popup = null;
  769. m.marker = null;
  770. }
  771. });
  772. state.markers = state.markers.filter(
  773. (m) => !locations.includes(m.locations),
  774. );
  775. state.positions = state.positions.filter((p) => !locations.includes(p));
  776. handleFitBounds();
  777. };
  778. const handleRemoveAllMarkers = () => {
  779. state.markers.forEach((m) => {
  780. m.marker?.remove();
  781. m.popup?.remove();
  782. });
  783. state.markers = [];
  784. state.positions = [];
  785. };
  786. const handleSetDetailMarker = (marker: MarkerType) => {
  787. handleRemoveAllMarkers();
  788. const locations = marker.locations?.split(',').map(Number);
  789. if (!locations) {
  790. ElMessage.error({ message: '该点位无地址经纬度' });
  791. return;
  792. }
  793. // 获取事件周围的 5km 内的 监控点
  794. const bounds: number[][] = new window.minemap.LngLat(...locations)
  795. .toBounds(10000)
  796. .toArray();
  797. const videos = store.videoSurveillance.reduce((carry, next) => {
  798. const [lng, lat] = next.locations?.split(',') ?? [];
  799. // bounds [right-bottom[lng, lat],left-top[lng, lat], ]
  800. if (
  801. Number(lng) > bounds[0][0] &&
  802. Number(lng) < bounds[1][0] &&
  803. Number(lat) > bounds[0][1] &&
  804. Number(lat) < bounds[1][1]
  805. ) {
  806. carry.push(next);
  807. }
  808. return carry;
  809. }, [] as MarkerType[]);
  810. // 开启路况信息
  811. if (!state.types.includes('路况信息')) {
  812. state.types.push('路况信息');
  813. state.hasTypes.push('路况信息');
  814. toggleControlTraffic();
  815. }
  816. handleAddMarkers('应急事件', [marker], icon_map_dpf);
  817. handleAddMarkers('视频监控', videos, icon_map_spjk);
  818. // state.markers[0].marker.togglePopup();
  819. };
  820. onMounted(async () => {
  821. window.minemap.util.getJSON(
  822. (import.meta.env.VITE_MAP_SERVER as string) +
  823. '/service/solu/style/id/12878',
  824. function (error, data) {
  825. data.layers.forEach(function (layer: any) {
  826. //判断是否道路线图层
  827. if (
  828. layer.type == 'line' &&
  829. layer.source == 'Traffic' &&
  830. layer['source-layer'] == 'Trafficrtic'
  831. ) {
  832. state.trafficLayerIds.push(layer.id);
  833. }
  834. });
  835. },
  836. );
  837. try {
  838. const html = document.createElement("div");
  839. actionTypes.value.forEach(atypes => {
  840. if (atypes?.action == null) return;
  841. const name = atypes.type;
  842. const c = (atypes?.action?.toString().split("handleAddMarkers"));
  843. if (c.length <= 1) return;
  844. const args1 = c[1].replaceAll("(","").replaceAll(")","");
  845. // debugger
  846. const args = args1.split(",");
  847. if (eval(args[2]) == undefined) return;
  848. const div = document.createElement("div");
  849. div.className = "tipitem"
  850. const imagee = renderElement((eval(args[2])));
  851. div.append(imagee);
  852. const c1 = document.createElement("span"); c1.innerHTML = (name);
  853. div.append(c1);
  854. html.append(div);
  855. });
  856. state.map["tipcontentRef"].append(html);
  857. } catch (ee) {
  858. }
  859. state.map.on('load', function () {
  860. updateTrafficSource();
  861. //如果底图没有配置路况图层,需要自己手动增加
  862. state.map.addLayer({
  863. id: 'trafficlines',
  864. type: 'line',
  865. source: 'Traffic',
  866. 'source-layer': 'Trafficrtic',
  867. layout: {
  868. 'line-join': 'round',
  869. 'line-cap': 'round',
  870. },
  871. paint: {
  872. 'line-color': {
  873. property: 'status',
  874. stops: [
  875. [0, '#999999'],
  876. [1, '#66cc00'],
  877. [2, '#ff9900'],
  878. [3, '#cc0000'],
  879. [4, '#9d0404'],
  880. ],
  881. },
  882. 'line-width': {
  883. stops: [
  884. [5, 1],
  885. [18, 3],
  886. ],
  887. base: 1.2,
  888. },
  889. },
  890. });
  891. state.trafficLayerIds.push('trafficlines');
  892. state.trafficStatus = false;
  893. updateTrafficLayerVisibility('none');
  894. store.getAllResources();
  895. store.getAllsingleDevice();
  896. store.getAllvideoDevice();
  897. store.getHDIncidentList();
  898. });
  899. if (!route.query.id) return;
  900. // 如果存在id
  901. await incidentStore.getIncidentItem(route.query.id as string);
  902. // @ts-ignore
  903. handleSetDetailMarker(incidentStore.incidentDetail.baseInfo ?? {});
  904. // const vPlayAreaEl = document.getElementById('vPlayArea');
  905. // vPlayAreaEl &&
  906. // (vPlayAreaEl.style.height = window.innerHeight - 20 + 'px');
  907. // window.theSocket && window.theSocket.resize();
  908. });
  909. emitter.on('dosearchstart', () => { handleRemoveMarkers('应急仓库', store.emergencyWarehouse);
  910. });
  911. emitter.on('dosearchend', () => {
  912. handleAddMarkers('应急仓库', store.emergencyWarehouse, icon_map_yjck);
  913. });
  914. onUnmounted(() => {
  915. emitter.off('dosearchstart', () => { });
  916. emitter.off('dosearchend', () => {});
  917. })
  918. watch(
  919. () => store?.currentIncident,
  920. (next) => {
  921. if (!isEmpty(next)) {
  922. handleSetDetailMarker({
  923. ...next,
  924. });
  925. } else {
  926. handleRemoveAllMarkers();
  927. if (state.types.includes('应急事件')) {
  928. state.types.forEach((next) => {
  929. actionTypes.value.forEach((item) => {
  930. if (next === item.type) {
  931. state.hasTypes.push(item.type);
  932. item.action();
  933. }
  934. });
  935. });
  936. } else {
  937. state.map?.flyTo({
  938. center: [118.29564, 33.97441],
  939. zoom: 14,
  940. bearing: 10,
  941. pitch: 30,
  942. duration: 2000,
  943. });
  944. }
  945. }
  946. },
  947. );
  948. watch(
  949. () => state.types,
  950. (next) => {
  951. actionTypes.value.forEach((item) => {
  952. if (next.includes(item.type) && !item.hasActioned) {
  953. state.hasTypes.push(item.type);
  954. item.action();
  955. }
  956. if (!next.includes(item.type) && item.hasActioned) {
  957. item.remove();
  958. }
  959. });
  960. },
  961. );
  962. return () => (
  963. <div class="task-map-container">
  964. <MapView v-model:map={state.map} />
  965. {/* <div style="width:35%;height:20%;background-color:blue"> */}
  966. {/*<div id='vPlayArea' style="width:30%;"/>*/}
  967. {/* </div> */}
  968. <div
  969. class={clsx('address-type-card-container', {
  970. ['in-detail']: props.readonly,
  971. })}>
  972. <Popup
  973. class={clsx('address-type-card', {
  974. ['in-detail']: props.readonly,
  975. })}>
  976. <el-checkbox-group v-model={state.types}>
  977. {adrsMapTypes.value &&
  978. adrsMapTypes.value?.map((t) => (
  979. <>
  980. {!t.disabled && (
  981. <el-checkbox key={t} class="card-item" label={t.name}>
  982. <span>
  983. <img class="tipicon" v-show={t.icon!=null} src={t.icon} />
  984. {t.name}
  985. </span>
  986. </el-checkbox>
  987. )}
  988. </>
  989. ))}
  990. </el-checkbox-group>
  991. <i class="card-border-bottom-left"></i>
  992. <i class="card-border-bottom-right"></i>
  993. </Popup>
  994. </div>
  995. </div>
  996. );
  997. },
  998. });