LayerAnalysis.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <template>
  2. <div class="menu-content">
  3. <div class="gradient-text common-dialog-title2">图层分析</div>
  4. <div class="scroll-box">
  5. <div class="box">
  6. <div
  7. v-for="(item, index) in dataList"
  8. :key="index"
  9. :class="item.checked ? 'box-item box-item-active' : 'box-item'"
  10. :title="item.name"
  11. @click="handleClick(item)"
  12. >
  13. <div class="text1">{{ item.name }}</div>
  14. <div class="text2">{{ item.value }}</div>
  15. </div>
  16. </div>
  17. <div class="box2">
  18. <div class="box2-title">各区县分布统计</div>
  19. <Chart :option="chartOption1" style="width: 100%; height: 350px" />
  20. </div>
  21. <div class="box2">
  22. <div class="box2-title">类型统计</div>
  23. <div class="box2-right">
  24. <Chart :option="chartOption2" style="width: 250px; height: 100%" />
  25. <div class="legend-box">
  26. <div v-for="(item, index) in legendData" :key="index" class="legend-item">
  27. <span class="dot" :style="{ backgroundColor: getColor(index) }"></span>{{ item.name }}:{{ item.value }}
  28. </div>
  29. </div>
  30. </div>
  31. </div>
  32. </div>
  33. </div>
  34. </template>
  35. <script lang="ts" setup>
  36. import { PointType } from '@/api/globalMap/type';
  37. import {
  38. getBuildingProjectType,
  39. getChemicalType,
  40. getChemicalWarehouseType,
  41. getConstructionSitesType,
  42. getCountPointInfo,
  43. getCountPointInfoAreaList,
  44. getCountPointInfoTypeErtongfulijigou,
  45. getCountPointInfoTypeMdpUnits,
  46. getCountPointInfoTypeYangLaoJiGou,
  47. getDroneType,
  48. getEmergencyDisasterInfoOfficerType,
  49. getEmergencyExpertType,
  50. getEmergencyShelterType,
  51. getEmergencyTransportResourcesType,
  52. getGasolineType,
  53. getHospitalType,
  54. getMajorHazardSourceType,
  55. getMidmapDzzhType,
  56. getMiningOperationsType,
  57. getMiningType,
  58. getRainPitsType,
  59. getRescueMateriaType,
  60. getSchoolType,
  61. getShipType,
  62. getStationInfoType,
  63. getTouristAttractionType,
  64. getWaterloggedRoadsType,
  65. getYardSitesType
  66. } from '@/api/globalMap/layerAnalysis';
  67. import { option4, option5 } from './echartOptions';
  68. import BigNumber from 'bignumber.js';
  69. interface Props {
  70. pointType: PointType[];
  71. }
  72. const props = withDefaults(defineProps<Props>(), {});
  73. let colorList = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
  74. let dataList = ref([]);
  75. let legendData = ref([]);
  76. let chartOption1 = reactive(option4);
  77. let chartOption2 = reactive(option5);
  78. const getColor = (index) => {
  79. if (colorList[index]) {
  80. return colorList[index];
  81. } else {
  82. return '#edf2fa';
  83. }
  84. };
  85. // 得到选中的标签的类型
  86. const getOption = (data, key = 'dataType') => {
  87. if (!data) {
  88. return;
  89. }
  90. let path = [];
  91. data.forEach((item) => {
  92. if (item.checked) {
  93. path.push(item[key]);
  94. }
  95. });
  96. return path.toString();
  97. };
  98. watch(
  99. () => props.pointType,
  100. () => {
  101. if (!props.pointType || props.pointType.length === 0) {
  102. return;
  103. }
  104. getCountPointInfo({ option: getOption(props.pointType, 'component') }).then((res) => {
  105. res.data.list.forEach((item) => {
  106. item.checked = true;
  107. });
  108. dataList.value = res.data.list;
  109. });
  110. },
  111. {
  112. immediate: true,
  113. deep: true
  114. }
  115. );
  116. watch(
  117. dataList,
  118. () => {
  119. const checkedData = dataList.value.filter((item) => {
  120. return item.checked;
  121. });
  122. if (!dataList.value || dataList.value.length === 0 || checkedData.length === 0) {
  123. chartOption1.yAxis.data = [];
  124. chartOption1.series[0].data = [];
  125. chartOption1.series[1].data = [];
  126. chartOption2.series[0].data = [];
  127. return;
  128. }
  129. // 各区县
  130. getCountPointInfoAreaList({ option: getOption(checkedData) }).then((res) => {
  131. const data = res.data.list;
  132. if (data.length > 0) {
  133. // 使用reduce方法合并相同area的num
  134. const mergedArray = data.reduce((acc, current) => {
  135. // 检查累加器(acc)中是否已有当前area
  136. const existing = acc.find((item) => item.area === current.area);
  137. if (existing) {
  138. // 如果存在,则累加num
  139. existing.num = BigNumber(existing.num).plus(current.num).toNumber();
  140. } else {
  141. // 如果不存在,则添加到累加器
  142. acc.push(current);
  143. }
  144. return acc;
  145. }, []);
  146. let yData = [];
  147. let seriesData = [];
  148. let seriesData2 = [];
  149. let maxData = [];
  150. let max = 0;
  151. mergedArray.forEach((item) => {
  152. yData.push(item.area);
  153. seriesData.push(item.num);
  154. if (item.num === 0) {
  155. seriesData2.push([item.num, null]);
  156. } else {
  157. seriesData2.push([item.num, item.area]);
  158. }
  159. if (item.num > max) {
  160. max = item.num;
  161. }
  162. });
  163. if (max === 0) {
  164. max = 50;
  165. } else {
  166. max = parseInt(new BigNumber(max).multipliedBy(new BigNumber(1.2)).toNumber());
  167. }
  168. for (let i = 0; i < seriesData.length; i++) {
  169. maxData.push(max);
  170. }
  171. chartOption1.yAxis.data = yData;
  172. chartOption1.xAxis.max = max;
  173. chartOption1.series[0].data = seriesData;
  174. chartOption1.series[1].data = seriesData2;
  175. chartOption1.series[2].data = maxData;
  176. }
  177. });
  178. // 类型统计
  179. if (checkedData.length === 1) {
  180. let methodList = {
  181. '1': getEmergencyExpertType,
  182. '2': getRescueMateriaType,
  183. '3': getEmergencyShelterType,
  184. '4': getWaterloggedRoadsType,
  185. '5': getSchoolType,
  186. '6': getHospitalType,
  187. '7': getGasolineType,
  188. '8': getMiningType,
  189. '11': getChemicalType,
  190. '10': getShipType,
  191. '12': getChemicalType,
  192. '13': getChemicalType,
  193. '14': getChemicalType,
  194. '15': getDroneType,
  195. '16': getRainPitsType,
  196. '17': getMidmapDzzhType,
  197. '18': getMiningOperationsType,
  198. '20': getCountPointInfoTypeMdpUnits,
  199. '21': getBuildingProjectType,
  200. '22': getChemicalWarehouseType,
  201. '23': getMajorHazardSourceType,
  202. '24': getStationInfoType,
  203. '25': getYardSitesType,
  204. '26': getTouristAttractionType,
  205. '27': getConstructionSitesType,
  206. '28': getEmergencyTransportResourcesType,
  207. '29': getEmergencyDisasterInfoOfficerType,
  208. '44': getCountPointInfoTypeErtongfulijigou,
  209. '45': getCountPointInfoTypeYangLaoJiGou
  210. };
  211. let method = methodList[dataList.value[0].dataType];
  212. if (!method) return;
  213. method().then((res) => {
  214. legendData.value = res.rows;
  215. chartOption2.legend = { show: false };
  216. chartOption2.series[0].data = res.rows;
  217. });
  218. } else {
  219. const tempData = [];
  220. checkedData.forEach((item) => {
  221. tempData.push(item);
  222. });
  223. legendData.value = tempData;
  224. chartOption2.legend = { show: false };
  225. chartOption2.series[0].data = checkedData;
  226. }
  227. },
  228. {
  229. immediate: true,
  230. deep: true
  231. }
  232. );
  233. const handleClick = (item) => {
  234. item.checked = !item.checked;
  235. };
  236. </script>
  237. <style lang="scss" scoped>
  238. .menu-content {
  239. width: 573px;
  240. height: 764px;
  241. background: url('@/assets/images/map/rightMenu/layerAnalysis/dialog.png') no-repeat;
  242. background-size: 100% 100%;
  243. padding: 60px 10px 10px 15px;
  244. font-size: 14px;
  245. position: relative;
  246. color: #fff;
  247. .scroll-box {
  248. width: 100%;
  249. height: 100%;
  250. position: relative;
  251. overflow-y: auto;
  252. }
  253. }
  254. .box {
  255. display: flex;
  256. flex-wrap: wrap;
  257. font-size: 14px;
  258. .box-item {
  259. display: flex;
  260. justify-content: space-between;
  261. padding: 12px 20px 0 20px;
  262. cursor: pointer;
  263. width: 184px;
  264. height: 43px;
  265. background: url('@/assets/images/map/rightMenu/layerAnalysis/tag.png') no-repeat;
  266. background-size: 100% 100%;
  267. margin-left: -4px;
  268. &:hover {
  269. background: url('@/assets/images/map/rightMenu/layerAnalysis/tagActive.png') no-repeat;
  270. background-size: 100% 100%;
  271. }
  272. .text1 {
  273. flex: 1;
  274. font-size: 14px;
  275. color: #ffffff;
  276. overflow: hidden;
  277. white-space: nowrap;
  278. text-overflow: ellipsis;
  279. margin-right: 10px;
  280. }
  281. .text2 {
  282. font-family: 'BEBAS-1';
  283. margin-left: 5px;
  284. font-size: 14px;
  285. color: #00e8ff;
  286. }
  287. }
  288. .box-item-active {
  289. background: url('@/assets/images/map/rightMenu/layerAnalysis/tagActive.png') no-repeat;
  290. background-size: 100% 100%;
  291. }
  292. }
  293. .box2 {
  294. margin-top: 7px;
  295. .box2-title {
  296. height: 27px;
  297. background: url('@/assets/images/map/rightMenu/titleBox2.png') no-repeat bottom left;
  298. background-size: 135px 20px;
  299. padding-left: 28px;
  300. font-size: 16px;
  301. color: #f4f7fa;
  302. }
  303. .box2-right {
  304. width: 100%;
  305. height: 230px;
  306. display: flex;
  307. align-items: flex-start;
  308. .legend-box {
  309. flex: 1;
  310. display: flex;
  311. flex-wrap: wrap;
  312. .legend-item {
  313. display: flex;
  314. align-items: center;
  315. margin-bottom: 10px;
  316. margin-right: 10px;
  317. }
  318. .dot {
  319. display: inline-block;
  320. width: 16px;
  321. height: 16px;
  322. border-radius: 50%;
  323. margin-right: 6px;
  324. }
  325. }
  326. }
  327. }
  328. </style>