FixedPointAnalysis.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. <template>
  2. <div class="menu-content">
  3. <div class="gradient-text title">定点分析</div>
  4. <div class="scroll-box">
  5. <div v-if="!tempState.address" class="search-box">
  6. <div class="text-box">
  7. <i class="icon-position2" />
  8. <div class="text1" :title="selectData.event_title">{{ selectData.event_title }}</div>
  9. </div>
  10. <div class="common-btn-primary3" @click="toSelect">定点选取</div>
  11. </div>
  12. <div v-else class="search-box">
  13. <div class="text-box">
  14. <i class="icon-position2" />
  15. <div class="text1" :title="tempState.address">{{ tempState.address }}</div>
  16. </div>
  17. <div class="common-btn-primary4" @click="confirmSelect">确定定位</div>
  18. </div>
  19. <div class="search-item">
  20. <div class="text1">选择救灾资源:</div>
  21. <el-select
  22. v-model="queryParams.dataType"
  23. class="custom-select select-box"
  24. placeholder="请选择"
  25. popper-class="custom-select-popper"
  26. :teleported="false"
  27. >
  28. <el-option v-for="item in disaster_relief_material" :key="item.value" :label="item.label" :value="item.value"></el-option>
  29. </el-select>
  30. </div>
  31. <div class="search-item2">
  32. <el-input v-model="queryParams.keyword" class="custom-input2" placeholder="请输入关键字搜索" />
  33. <div class="common-btn-primary4" @click="getList">搜索</div>
  34. </div>
  35. <div class="search-item3">
  36. <el-checkbox v-model="checked1">自定义距离</el-checkbox>
  37. <el-input v-model="distance" class="custom-input2" placeholder="自定义距离(公里)" />
  38. <div class="common-btn3" @click="getList">确定</div>
  39. </div>
  40. <div class="list2">
  41. <div class="text-box1">
  42. 总数:
  43. <div class="gradient-text2">{{ total }}</div>
  44. </div>
  45. <div class="list-content">
  46. <div v-for="(item, index) in dataList" :key="index" class="list-item" @click="handleRoutes(item)">
  47. <div class="text-box2">
  48. <div class="text2">{{ item.name }}</div>
  49. <div class="text3">{{ item.address }}</div>
  50. </div>
  51. <div class="operate">
  52. <i class="icon2" />
  53. 路线
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. <div v-show="showAddress && !!routeData && routeData.length > 0" class="route-box">
  59. <div class="route-item1">
  60. <i class="icon-position3" />
  61. <div class="text1">路线始点:</div>
  62. <div class="text2" :title="routesAddress">{{ routesAddress }}</div>
  63. <i class="icon-close2" @click="showAddress = false" />
  64. </div>
  65. <div class="route-list">
  66. <div
  67. v-for="(item, index) in routeData"
  68. :key="index"
  69. :class="index === selectIndex ? 'route-item2 route-item2-active' : 'route-item2'"
  70. @click="drawRoute(item, index)"
  71. >
  72. <div class="text-box1">
  73. <div :class="'tag tag' + index">{{ getTag(index) }}</div>
  74. <!-- <div class="text1">{{ item.strategy }}</div>-->
  75. </div>
  76. <div class="route-info">
  77. <div class="text-box2">
  78. <i class="icon1" />
  79. <div class="gradient-text2">{{ item.duration[0] }}</div>
  80. <div class="text2">小时</div>
  81. <div class="gradient-text2">{{ item.duration[1] }}</div>
  82. <div class="text2">分钟</div>
  83. </div>
  84. <div class="line"></div>
  85. <div class="text-box2">
  86. <i class="icon2" />
  87. <div class="gradient-text2">{{ item.distance / 1000 }}</div>
  88. <div class="text2">公里</div>
  89. </div>
  90. </div>
  91. </div>
  92. </div>
  93. </div>
  94. </div>
  95. </div>
  96. </template>
  97. <script lang="ts" setup name="FixedPointAnalysis">
  98. import BigNumber from 'bignumber.js';
  99. import { getEmergencyRescuePointInfoList } from '@/api/globalMap';
  100. import markImg from '@/assets/images/map/mark.png';
  101. import startImg from '@/assets/images/map/start.png';
  102. import endImg from '@/assets/images/map/end.png';
  103. interface Props {
  104. location?: string | number[];
  105. activeMap: string;
  106. }
  107. const AMapType = ['vectorgraph', 'satellite'];
  108. const props = withDefaults(defineProps<Props>(), {});
  109. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  110. const { disaster_relief_material } = toRefs<any>(proxy?.useDict('disaster_relief_material'));
  111. import gcoord from 'gcoord';
  112. import Icon from 'ol/style/Icon';
  113. import Feature from 'ol/Feature';
  114. import Point from 'ol/geom/Point';
  115. import Style from 'ol/style/Style';
  116. import { LineString } from 'ol/geom';
  117. import { Stroke } from 'ol/style';
  118. import useMapStore from '@/store/modules/map';
  119. const mapStore = useMapStore();
  120. const amapKey = 'e45d4caa2bef3c84714a2ed9b1e27d98';
  121. let getMapUtils = inject('getMapUtils');
  122. let showAddress = ref(true);
  123. let routeData = ref([]);
  124. let routeLine, startMarker, endMarker;
  125. let routesAddress = ref('');
  126. let AMap, map;
  127. let eventList = ref([]);
  128. let selectData = ref({
  129. event_title: '',
  130. longitude: '',
  131. latitude: ''
  132. });
  133. let selectMarker;
  134. let tempState = reactive({
  135. address: '',
  136. longitude: '',
  137. latitude: ''
  138. });
  139. let checked1 = ref(false);
  140. let distance = ref('');
  141. let queryParams = reactive({
  142. keyword: '',
  143. dataType: '2'
  144. });
  145. let total = ref(0);
  146. let dataList = ref([]);
  147. const toSelect = () => {
  148. map.on('click', handleClickMap);
  149. mapStore.setIsMapSelect(true);
  150. showAddress.value = false;
  151. routeData.value = [];
  152. clearMarker();
  153. clearLine();
  154. };
  155. const handleClickMap = (e) => {
  156. if (AMapType.includes(props.activeMap)) {
  157. map.off('click', handleClickMap);
  158. } else {
  159. map.un('click', handleClickMap);
  160. }
  161. mapStore.setIsMapSelect(false);
  162. getAddress([e.lnglat.getLng(), e.lnglat.getLat()]);
  163. };
  164. const confirmSelect = () => {
  165. selectEvent(
  166. {
  167. event_title: tempState.address,
  168. longitude: tempState.longitude,
  169. latitude: tempState.latitude
  170. },
  171. true
  172. );
  173. };
  174. // 选中事件
  175. const selectEvent = (item, unFitView) => {
  176. eventList.value.forEach((item2) => {
  177. if (item2.event_id === item.event_id) {
  178. item2.checked = true;
  179. } else {
  180. item2.checked = false;
  181. }
  182. });
  183. selectData.value = item;
  184. tempState.address = '';
  185. tempState.longitude = '';
  186. tempState.latitude = '';
  187. getList();
  188. };
  189. const createMarks = (item, unFitView) => {
  190. clearMarker();
  191. if (AMapType.includes(props.activeMap)) {
  192. // 以 icon URL 的形式创建一个途经点
  193. const icon = new AMap.Icon({
  194. size: new AMap.Size(19, 31),
  195. image: markImg
  196. });
  197. selectMarker = new AMap.Marker({
  198. position: new AMap.LngLat(item.longitude, item.latitude),
  199. icon: icon,
  200. offset: new AMap.Pixel(-13, -30)
  201. });
  202. selectMarker.setMap(map);
  203. if (!unFitView) {
  204. map.setFitView([selectMarker]);
  205. }
  206. } else {
  207. const icon = new Icon({
  208. src: markImg,
  209. width: 19,
  210. height: 31
  211. });
  212. const feature = new Feature({
  213. geometry: new Point([item.longitude, item.latitude])
  214. });
  215. feature.setStyle(
  216. new Style({
  217. image: icon
  218. })
  219. );
  220. const vectorLayer = getMapUtils().getVectorLayer();
  221. vectorLayer.getSource().addFeature(feature);
  222. if (!unFitView) {
  223. map.getView().setCenter([item.longitude, item.latitude]);
  224. }
  225. }
  226. };
  227. let selectIndex = ref(-1);
  228. const handleRoutes = async (item) => {
  229. selectIndex.value = -1;
  230. const lnglat = gcoord.transform([item.longitude, item.latitude], gcoord.WGS84, gcoord.GCJ02);
  231. const lnglat2 = gcoord.transform([selectData.value.longitude, selectData.value.latitude], gcoord.WGS84, gcoord.GCJ02);
  232. const start = [lnglat[0].toFixed(6), lnglat[1].toFixed(6)];
  233. const end = [lnglat2[0].toFixed(6), lnglat2[1].toFixed(6)];
  234. showAddress.value = true;
  235. routesAddress.value = item.address;
  236. const url = `https://restapi.amap.com/v5/direction/driving?origin=${start.toString()}&destination=${end.toString()}&key=${amapKey}`;
  237. const response = await fetch(url + '&strategy=32&show_fields=polyline,cost');
  238. if (!!response.ok) {
  239. const data = await response.json();
  240. if (data.route && data.route.paths) {
  241. data.route.paths.forEach((item) => {
  242. item.duration = formatDate(item.cost?.duration);
  243. });
  244. routeData.value = data.route.paths;
  245. // 默认展示第一条
  246. drawRoute(routeData.value[0], 0);
  247. } else {
  248. routeData.value = [];
  249. }
  250. }
  251. };
  252. const drawRoute = (route, index) => {
  253. selectIndex.value = index;
  254. const path = parseRouteToPath(route);
  255. clearLine();
  256. if (AMapType.includes(props.activeMap)) {
  257. const icon1 = new AMap.Icon({
  258. size: new AMap.Size(19, 31),
  259. image: startImg
  260. });
  261. const icon2 = new AMap.Icon({
  262. size: new AMap.Size(19, 31),
  263. image: endImg
  264. });
  265. startMarker = new AMap.Marker({
  266. position: path[0],
  267. icon: icon1,
  268. offset: new AMap.Pixel(-13, -30),
  269. map: map
  270. });
  271. endMarker = new AMap.Marker({
  272. position: path[path.length - 1],
  273. icon: icon2,
  274. offset: new AMap.Pixel(-13, -30),
  275. map: map
  276. });
  277. routeLine = new AMap.Polyline({
  278. path: path,
  279. isOutline: true,
  280. outlineColor: '#ffeeee',
  281. borderWeight: 2,
  282. strokeWeight: 5,
  283. strokeColor: '#0091ff',
  284. lineJoin: 'round'
  285. });
  286. routeLine.setMap(map);
  287. // 调整视野达到最佳显示区域
  288. map.setFitView([startMarker, endMarker, routeLine]);
  289. } else {
  290. const vectorLayer = getMapUtils().getVectorLayer();
  291. const source = vectorLayer.getSource();
  292. startMarker = new Feature({
  293. geometry: new Point(path[0])
  294. });
  295. endMarker = new Feature({
  296. geometry: new Point(path[path.length - 1])
  297. });
  298. startMarker.setStyle(
  299. new Style({
  300. image: new Icon({
  301. src: startImg,
  302. width: 19,
  303. height: 31
  304. })
  305. })
  306. );
  307. endMarker.setStyle(
  308. new Style({
  309. image: new Icon({
  310. src: endImg,
  311. width: 19,
  312. height: 31
  313. })
  314. })
  315. );
  316. routeLine = new Feature({
  317. geometry: new LineString(path)
  318. });
  319. routeLine.setStyle(
  320. new Style({
  321. stroke: new Stroke({
  322. color: '#0091ff', // 主线条颜色
  323. width: 5, // 主线条宽度
  324. lineCap: 'round', // 线帽样式(可选)
  325. lineJoin: 'round' // 线连接样式
  326. })
  327. })
  328. );
  329. source.addFeature(startMarker);
  330. source.addFeature(routeLine);
  331. source.addFeature(endMarker);
  332. }
  333. };
  334. // 解析DrivingRoute对象,构造成AMap.Polyline的path参数需要的格式
  335. // DrivingResult对象结构参考文档 https://lbs.amap.com/api/javascript-api/reference/route-search#m_DriveRoute
  336. const parseRouteToPath = (route) => {
  337. var path = [];
  338. for (var i = 0, l = route.steps.length; i < l; i++) {
  339. var step = route.steps[i];
  340. // 按分号分割字符串,得到一个包含经纬度对的数组
  341. const coordinatesPairs = step.polyline.split(';');
  342. // 将每个经纬度对进一步分割成经度和纬度,并转换为一个对象
  343. path = coordinatesPairs.map((pair) => {
  344. const [longitude, latitude] = pair.split(',');
  345. return gcoord.transform([longitude, latitude], gcoord.GCJ02, gcoord.WGS84);
  346. });
  347. }
  348. return path;
  349. };
  350. function formatDate(seconds: number) {
  351. // 将秒数转换为BigNumber
  352. const secondsBn = new BigNumber(seconds);
  353. // 计算小时数
  354. const hoursBn = secondsBn.dividedBy(3600).integerValue(BigNumber.ROUND_DOWN);
  355. // 计算剩余的秒数,然后转换为分钟数
  356. const remainingSecondsBn = secondsBn.minus(hoursBn.times(3600));
  357. const minutesBn = remainingSecondsBn.dividedBy(60).integerValue();
  358. // 将BigNumber转换为字符串,并使用padStart添加前导零
  359. const hours = hoursBn.toString();
  360. const minutes = minutesBn.toString();
  361. // 返回包含小时和分钟的数组
  362. return [hours, minutes];
  363. }
  364. const getTag = (index) => {
  365. const arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
  366. return '路线' + (arr[index] ? arr[index] : index);
  367. };
  368. // 搜索列表
  369. const getList = () => {
  370. const params = {
  371. longitude: selectData.value.longitude,
  372. latitude: selectData.value.latitude,
  373. dataType: queryParams.dataType,
  374. keyword: queryParams.keyword,
  375. radius: '30'
  376. };
  377. if (!!checked1.value) {
  378. params.radius = distance.value;
  379. }
  380. getEmergencyRescuePointInfoList(params).then((res) => {
  381. dataList.value = res.rows;
  382. total.value = res.total;
  383. });
  384. };
  385. const getAddress = async (location) => {
  386. const gcj02Coord = gcoord.transform(location, gcoord.WGS84, gcoord.GCJ02);
  387. tempState.longitude = location[0];
  388. tempState.latitude = location[1];
  389. // 调用高德逆向地理编码 API
  390. const response = await fetch(`https://restapi.amap.com/v3/geocode/regeo?key=${amapKey}&location=${gcj02Coord[0]},${gcj02Coord[1]}`);
  391. const result = await response.json();
  392. // 解析地址信息
  393. if (result.status === '1' && result.regeocode) {
  394. tempState.address = result.regeocode.formatted_address;
  395. }
  396. createMarks({ longitude: location[0], latitude: location[1] }, true);
  397. };
  398. const clearMarker = () => {
  399. if (!selectMarker) return;
  400. if (AMapType.includes(props.activeMap)) {
  401. selectMarker.remove();
  402. selectMarker = null;
  403. } else {
  404. const vectorLayer = getMapUtils().getVectorLayer();
  405. const source = vectorLayer.getSource();
  406. source.removeFeature(selectMarker);
  407. selectMarker = null;
  408. }
  409. };
  410. const clearLine = () => {
  411. if (AMapType.includes(props.activeMap)) {
  412. if (!!startMarker) {
  413. startMarker.remove();
  414. startMarker = null;
  415. }
  416. if (!!endMarker) {
  417. endMarker.remove();
  418. endMarker = null;
  419. }
  420. if (!!routeLine) {
  421. routeLine.remove();
  422. routeLine = null;
  423. }
  424. } else {
  425. const vectorLayer = getMapUtils().getVectorLayer();
  426. const source = vectorLayer.getSource();
  427. if (!!startMarker) {
  428. source.removeFeature(startMarker);
  429. startMarker = null;
  430. }
  431. if (!!endMarker) {
  432. source.removeFeature(endMarker);
  433. endMarker = null;
  434. }
  435. if (!!routeLine) {
  436. source.removeFeature(routeLine);
  437. routeLine = null;
  438. }
  439. }
  440. };
  441. onMounted(() => {
  442. map = getMapUtils().getMap();
  443. if (AMapType.includes(props.activeMap)) {
  444. AMap = getMapUtils().getAMap();
  445. }
  446. getAddress(props.location);
  447. });
  448. </script>
  449. <style lang="scss" scoped>
  450. .menu-content {
  451. width: 1500px;
  452. height: 2071px;
  453. background: url('@/assets/images/map/rightMenu/dialog2.png') no-repeat;
  454. padding: 130px 45px 20px 50px;
  455. font-size: 36px;
  456. position: relative;
  457. color: #ffffff;
  458. .scroll-box {
  459. width: 100%;
  460. height: 100%;
  461. position: relative;
  462. overflow-y: auto;
  463. }
  464. .search-box {
  465. width: 100%;
  466. height: 150px;
  467. background: url('@/assets/images/electronicDisasterMapManage/box6.png') no-repeat;
  468. background-size: 100% 100%;
  469. padding: 0 10px 0 30px;
  470. display: flex;
  471. justify-content: space-between;
  472. align-items: center;
  473. .text-box {
  474. display: flex;
  475. align-items: center;
  476. .icon-position2 {
  477. flex-shrink: 0;
  478. display: inline-block;
  479. width: 46px;
  480. height: 50px;
  481. background: url('@/assets/images/electronicDisasterMapManage/position2.png') no-repeat;
  482. background-size: 100% 100%;
  483. }
  484. .text1 {
  485. margin-left: 10px;
  486. font-size: 38px;
  487. color: #f7f8fb;
  488. display: -webkit-box;
  489. -webkit-box-orient: vertical;
  490. -webkit-line-clamp: 2;
  491. overflow: hidden;
  492. text-overflow: ellipsis;
  493. }
  494. }
  495. .common-btn-primary4 {
  496. flex-shrink: 0;
  497. }
  498. }
  499. .search-item {
  500. margin: 6px 0 3px;
  501. display: flex;
  502. align-items: center;
  503. .text1 {
  504. font-size: 38px;
  505. flex-shrink: 0;
  506. }
  507. .custom-select {
  508. flex: 1;
  509. }
  510. }
  511. .search-item2 {
  512. margin: 3px 0;
  513. display: flex;
  514. align-items: center;
  515. .custom-input2 {
  516. flex: 1;
  517. }
  518. .common-btn-primary4 {
  519. flex-shrink: 0;
  520. margin-right: -12px;
  521. }
  522. }
  523. .search-item3 {
  524. margin: 3px 0;
  525. display: flex;
  526. align-items: center;
  527. :deep(.el-checkbox) {
  528. color: #8fa8be;
  529. margin-right: 10px;
  530. flex-shrink: 0;
  531. .el-checkbox__inner {
  532. width: 28px;
  533. height: 28px;
  534. &::after {
  535. width: 6px;
  536. height: 14px;
  537. left: 8px;
  538. top: 4px;
  539. }
  540. }
  541. .el-checkbox__label {
  542. font-size: 38px;
  543. }
  544. }
  545. .custom-input2 {
  546. flex: 1;
  547. margin-right: 10px;
  548. }
  549. .common-btn3 {
  550. flex-shrink: 0;
  551. }
  552. }
  553. .list2 {
  554. padding: 8px;
  555. border-radius: 2px;
  556. background: #1c356d;
  557. color: #ebf5f7;
  558. .text-box1 {
  559. font-size: 38px;
  560. .gradient-text2 {
  561. font-size: 44px;
  562. font-family: BEBAS-1;
  563. }
  564. }
  565. .list-content {
  566. height: 560px;
  567. overflow-y: auto;
  568. .list-item {
  569. display: flex;
  570. justify-content: space-between;
  571. align-items: center;
  572. padding: 7px 0;
  573. border-bottom: 1px solid #4574d5;
  574. cursor: pointer;
  575. .text-box2 {
  576. .text2 {
  577. font-size: 38px;
  578. line-height: 76pxpx;
  579. }
  580. .text3 {
  581. font-size: 36px;
  582. line-height: 72px;
  583. }
  584. }
  585. .operate {
  586. flex-shrink: 0;
  587. display: flex;
  588. align-items: center;
  589. font-size: 38px;
  590. color: transparent;
  591. background-image: linear-gradient(to bottom, #ffffff 25%, #2b72d6 100%);
  592. -webkit-background-clip: text;
  593. background-clip: text;
  594. cursor: pointer;
  595. .icon2 {
  596. display: inline-block;
  597. width: 33px;
  598. height: 33px;
  599. background: url('@/assets/images/electronicDisasterMapManage/icon2.png') no-repeat;
  600. background-size: 100% 100%;
  601. }
  602. }
  603. }
  604. }
  605. }
  606. .route-box {
  607. .route-item1 {
  608. display: flex;
  609. align-items: center;
  610. background-color: #1d366e;
  611. padding: 0 10px;
  612. margin-top: 12px;
  613. .icon-position3 {
  614. display: inline-block;
  615. width: 23px;
  616. height: 26px;
  617. background: url('@/assets/images/electronicDisasterMapManage/position3.png') no-repeat;
  618. background-size: 100% 100%;
  619. flex-shrink: 0;
  620. }
  621. .text1 {
  622. font-size: 38px;
  623. color: #cfe4fe;
  624. flex-shrink: 0;
  625. }
  626. .text2 {
  627. font-size: 38px;
  628. color: #f1fbff;
  629. flex: 1;
  630. overflow: hidden;
  631. text-overflow: ellipsis;
  632. white-space: nowrap;
  633. }
  634. .icon-close2 {
  635. flex-shrink: 0;
  636. width: 30px;
  637. height: 30px;
  638. background: url('@/assets/images/electronicDisasterMapManage/close.png') no-repeat;
  639. background-size: 100% 100%;
  640. cursor: pointer;
  641. margin-left: 5px;
  642. }
  643. }
  644. .route-item2 {
  645. width: 100%;
  646. background: #1f2c4e;
  647. padding: 5px;
  648. margin-top: 15px;
  649. cursor: pointer;
  650. &:hover {
  651. border: 3px solid #01e3fb;
  652. }
  653. .text-box1 {
  654. display: flex;
  655. padding: 0 15px;
  656. .tag {
  657. color: #fff;
  658. background-color: #2c81ff;
  659. border-radius: 10px;
  660. padding: 2px 6px;
  661. font-size: 36px;
  662. margin-right: 10px;
  663. }
  664. .tag0 {
  665. color: #fff;
  666. background-color: #e65d63;
  667. }
  668. .tag1 {
  669. color: #fff;
  670. background-color: #f0b13c;
  671. }
  672. .tag2 {
  673. color: #fff;
  674. background-color: #6bc26b;
  675. }
  676. .text1 {
  677. font-size: 38px;
  678. margin-left: 5px;
  679. }
  680. }
  681. .route-info {
  682. background-color: #2b3858;
  683. border: 1px solid #2e5174;
  684. padding: 5px 15px;
  685. margin-top: 10px;
  686. display: flex;
  687. align-items: center;
  688. .text-box2 {
  689. display: flex;
  690. align-items: center;
  691. .icon1 {
  692. display: inline-block;
  693. width: 38px;
  694. height: 34px;
  695. background: url('@/assets/images/electronicDisasterMapManage/icon3.png') no-repeat;
  696. background-size: 100% 100%;
  697. margin-right: 15px;
  698. }
  699. .icon2 {
  700. display: inline-block;
  701. width: 34px;
  702. height: 42px;
  703. background: url('@/assets/images/electronicDisasterMapManage/icon4.png') no-repeat;
  704. background-size: 100% 100%;
  705. margin-right: 15px;
  706. }
  707. .gradient-text2 {
  708. font-size: 40px;
  709. font-family: BEBAS-1;
  710. margin: 0 3px;
  711. }
  712. .text2 {
  713. font-size: 38px;
  714. color: #95a9c1;
  715. }
  716. }
  717. .line {
  718. width: 1px;
  719. height: 10px;
  720. background-color: #5a6885;
  721. margin: 0 20px;
  722. }
  723. }
  724. }
  725. .route-item2-active {
  726. border: 3px solid #01e3fb;
  727. }
  728. }
  729. }
  730. .title {
  731. font-size: 60px;
  732. position: absolute;
  733. top: 30px;
  734. left: 140px;
  735. }
  736. </style>