MultiLevelQuery.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. <template>
  2. <el-tabs class="multi_level_query_table" v-model="activeName" @tab-click="handleClick" @tab-remove="removeTab"
  3. v-if="store.state.query_pick_last_pane">
  4. <el-tab-pane :label="store.state.query_pick_last_pane.name" name="second">
  5. <div class="list_vector_multi" v-for="(item_last, index) in store.state.query_pick_last_pane.value" :key="index"
  6. v-if="item_last.filed != 'geom'">
  7. <span>{{ item_last.filedZH }}:
  8. {{ item_last.filedZH == '面积' ? item_last.data.toFixed(2) : item_last.data }}</span>
  9. </div>
  10. </el-tab-pane>
  11. <el-tab-pane :closable="item.close" :label="item.name" :name="item.name"
  12. v-for="(item, index) in store.state.query_pick_pane" :key="index">
  13. <pie class="echart" :class="item.name == '权属' ? 'echart1' : ''" unit="亩"
  14. @echartClick="(name) => echartClick(name, item.value)" :ref="`echartRef`"></pie>
  15. <div>{{ eclickname }}</div>
  16. <el-collapse v-for="(value, index_item) in echartList[eclickname]" :key="index_item" @change="handleChange">
  17. <el-collapse-item :title="'地块' + (index_item + 1)" name="1">
  18. <div class="list_vector_multi" v-for="(value_field, index_field) in value" :key="index_field"
  19. @click="go(value)" v-if="value_field.filed != 'geom'">
  20. <div class="filed_box">
  21. {{ value_field.filedZH }}
  22. </div>
  23. :
  24. <div class="filed_box">
  25. {{ value_field.filedZH == '面积' ? value_field.data.toFixed(2) : value_field.data }}
  26. </div>
  27. </div>
  28. </el-collapse-item>
  29. </el-collapse>
  30. </el-tab-pane>
  31. <el-tab-pane label="自定义" name="自定义">自定义</el-tab-pane>
  32. </el-tabs>
  33. </template>
  34. <script>
  35. //这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  36. import { GetTableData } from '@/api/cockpitNew'
  37. import * as wellknown from "wellknown";
  38. import * as turf from "@turf/turf";
  39. import pie from "@/components/echartsTemplate/pie.vue";
  40. let manager_multi_level_query = null;
  41. let pick_entity = null;
  42. let manager_multi_level_vector = null;
  43. let query_click_by_iserver = null;
  44. export default {
  45. components: { pie },
  46. data() {
  47. return {
  48. activeName: 'second',
  49. handler_multi_level_query: null,
  50. manager_multi_level_query: null,
  51. manager_multi_level_vector: null,
  52. pick_entity: null,
  53. pick_entity_geo: null,
  54. eclickname: '',
  55. echartList: {}
  56. };
  57. },
  58. //监听属性 类似于data概念
  59. computed: {},
  60. //监控data中的数据变化
  61. watch: {},
  62. //方法集合
  63. methods: {
  64. removeTab(targetName) {
  65. let tabs = store.state.query_pick_pane;
  66. let activeName = this.activeName;
  67. if (activeName === targetName) {
  68. tabs.forEach((tab, index) => {
  69. if (tab.name === targetName) {
  70. let nextTab = tabs[index + 1] || tabs[index - 1];
  71. if (nextTab) {
  72. activeName = nextTab.name;
  73. }
  74. }
  75. });
  76. }
  77. this.activeName = activeName;
  78. store.state.query_pick_pane = tabs.filter(tab => tab.name !== targetName);
  79. },
  80. compute(mj) {
  81. return mj ? (mj * 0.0015).toFixed(2) : 0;
  82. },
  83. setEchart(data, type, index) {
  84. this.$nextTick(() => {
  85. let max = index == 0 ? 3 : 10
  86. let legend_right = index == 0 ? "2%" : "10%"
  87. this.$refs.echartRef[index].setOptions({ data, type, max, legend_right });
  88. });
  89. },
  90. echartClick(name, datas) {
  91. this.eclickname = name
  92. // let click = datas.filter((c) => c.name == name);
  93. // if (click.length > 0) this.gogeojson(click[0].geom );
  94. },
  95. switch_show(flag) {
  96. pick_entity.entities.values.forEach((res) => {
  97. res.show = flag;
  98. })
  99. },
  100. go(e) {
  101. const that = this;
  102. e.forEach(element => {
  103. if (element.filed == "geom") {
  104. this.gogeojson(element.data)
  105. }
  106. });
  107. },
  108. gogeojson(data) {
  109. let geojson = wellknown.parse(data);
  110. const twoDArray = geojson.coordinates[0];
  111. const oneDArray = twoDArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
  112. this.pick_entity_geo = oneDArray;
  113. pick_entity.entities.add({
  114. polygon: {
  115. // 获取指定属性(positions,holes(图形内需要挖空的区域))
  116. hierarchy: {
  117. positions: Cesium.Cartesian3.fromDegreesArray(oneDArray),
  118. },
  119. // 边框
  120. outline: true,
  121. // 边框颜色
  122. outlineColor: Cesium.Color.RED,
  123. // 边框尺寸
  124. outlineWidth: 2,
  125. // 填充的颜色,withAlpha透明度
  126. material: Cesium.Color.GREEN.withAlpha(0),
  127. // 是否被提供的材质填充
  128. fill: true,
  129. // 恒定高度
  130. height: 1.1,
  131. // 显示在距相机的距离处的属性,多少区间内是可以显示的
  132. // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(1000, 10000000),
  133. // 是否显示
  134. show: true,
  135. // 顺序,仅当`clampToGround`为true并且支持地形上的折线时才有效。
  136. zIndex: 10
  137. }
  138. });
  139. let flag = true;
  140. let time = setInterval(() => {
  141. flag = !flag
  142. this.switch_show(flag);
  143. }, 500);
  144. setTimeout(() => {
  145. clearInterval(time);
  146. pick_entity.entities.values.forEach((res) => {
  147. pick_entity.entities.remove(res);
  148. })
  149. }, 6000)
  150. // 注意:polygon首尾坐标要一致
  151. var polygon = turf.polygon([geojson.coordinates[0]]);
  152. var centroid = turf.centroid(polygon).geometry.coordinates;
  153. viewer.camera.flyTo({
  154. duration: 1,
  155. destination: Cesium.Cartesian3.fromDegrees(centroid[0], centroid[1], 3000),
  156. // destination: {
  157. // x: -6283267.004204832,
  158. // y: 28123682.896774407,
  159. // z: 23709669.98539126
  160. // },
  161. orientation: {
  162. heading: 6.149339593573709,
  163. pitch: -1.539825618847483,
  164. roll: 0
  165. },
  166. });
  167. },
  168. handleChange(val) {
  169. // console.log(val);
  170. },
  171. handleClick(tab, event) {
  172. this.eclickname = ''
  173. // console.log(tab, event);
  174. },
  175. init_handler() {
  176. const that = this;
  177. that.clear_data();
  178. if (that.handler_multi_level_query == null) {
  179. that.handler_multi_level_query = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  180. }
  181. that.handler_multi_level_query.setInputAction(async event => {
  182. let pickObj = viewer.scene.pick(event.position);
  183. var position = viewer.scene.pickPosition(event.position);
  184. if (!position)//点击到地球之外
  185. return false;
  186. var cartographic = Cesium.Cartographic.fromCartesian(position);
  187. let longitude = Cesium.Math.toDegrees(cartographic.longitude);
  188. let latitude = Cesium.Math.toDegrees(cartographic.latitude);
  189. let height = cartographic.height;
  190. let heading = viewer.scene.camera.heading;
  191. let pitch = viewer.scene.camera.pitch;
  192. // that.addSceneFun()
  193. if (!position) {
  194. position = Cesium.Cartesian3.fromDegrees(0, 0, 0);
  195. }
  196. manager_multi_level_query.entities.add({
  197. name: "manager_multi_level_query",
  198. position: Cesium.Cartesian3.fromDegrees(longitude, latitude, 40),
  199. billboard: {
  200. // 图像地址,URI或Canvas的属性
  201. image: "./static/images/overview/go.png",
  202. height: 34,
  203. width: 36,
  204. scale: 1.0,
  205. zIndex: 2,
  206. show: true
  207. },
  208. })
  209. const geojsonPoint = {
  210. "type": "Point",
  211. "coordinates": [longitude, latitude] // 注意经纬度顺序
  212. };
  213. const wkt = wellknown.stringify(geojsonPoint);
  214. // let id = store.state.vectorlayerlist[store.state.vectorlayerlist.length - 1].id
  215. let obj = {
  216. // "wkt": 'POINT (109.51207847188947 18.311530254307392)', //单面
  217. "wkt": 'POINT (109.50728022974468 18.318266593715794)', //多面
  218. // "wkt": wkt,
  219. "id": 'dd699f839bc04969ae2dc2e1964d0ad1',
  220. // "id": id,
  221. }
  222. GetTableData(obj).then(res => {
  223. if (res.data.data != undefined) {
  224. store.state.query_pick_last_pane = {
  225. name: res.data.dataname,
  226. value: res.data.data[0],
  227. close: 'closable'
  228. };
  229. }
  230. if (res.data.child != undefined) {
  231. store.state.query_pick_pane = [];
  232. let index = -1;
  233. res.data.child.forEach(element => {
  234. if (element.data.length > 1) {
  235. index++;
  236. let edata = []
  237. store.state.query_pick_pane.push({
  238. name: element.dataname,
  239. value: [],// element.data
  240. close: 'closable'
  241. });
  242. element.data.forEach(e => {
  243. e.forEach((res) => {
  244. if (res.filed == 'geom') {
  245. let geojson = wellknown.parse(res.data);
  246. // that.draw_vector(geojson, e,); 暂时不绘制面
  247. }
  248. })
  249. });
  250. // if(element.dataname == '土地现状'){
  251. const countByName = element.data.reduce((acc, e) => {
  252. let name, value = ''
  253. e.forEach((res) => {
  254. if (res.filed == 'dlmc' || res.filed == 'qslx') name = res.data
  255. if (res.filed == 'siweiarea') value = res.data
  256. })
  257. acc[name] = (acc[name] || 0) + value;
  258. if (element.dataname == '权属') {
  259. if (!this.echartList[name]) this.echartList[name] = []
  260. this.echartList[name].push(e)
  261. }
  262. return acc;
  263. }, {});
  264. Object.keys(countByName).forEach((key) => {
  265. edata.push({ name: key, value: this.compute(countByName[key]) })
  266. });
  267. edata.sort((a, b) => b.value - a.value);
  268. // }
  269. this.setEchart(edata, 'vertical', index)
  270. // store.state.query_pick_pane.push({
  271. // name: element.dataname,
  272. // value: element.data,
  273. // });
  274. // that.draw_vector(e);
  275. }
  276. });
  277. }
  278. })
  279. this.highlightResults(longitude, latitude);
  280. that.handler_multi_level_query.destroy();
  281. that.handler_multi_level_query = null;
  282. }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  283. },
  284. async highlightResults(longitude, latitude) {
  285. // 高亮结果
  286. let queryByIDParameters = {
  287. getFeatureMode: "BUFFER",
  288. // getFeatureMode: "SPATIAL",
  289. spatialQueryMode: "INTERSECT",
  290. datasetNames: store.state.vectorlayerlist[store.state.vectorlayerlist.length - 1].source.split(","),
  291. geometry: {
  292. parts: [1],
  293. points: [{ y: latitude, x: longitude }],
  294. type: "POINT",
  295. },
  296. bufferDistance: 0.00005,
  297. hasGeometry: true,
  298. };
  299. let response = await axios.post(this.calcIserverURI(store.state.vectorlayerlist[store.state.vectorlayerlist.length - 1].url), queryByIDParameters);
  300. const outputCoords = this.convertCoordinates(response.data.features[0].geometry.points);
  301. outputCoords.push(outputCoords[0])
  302. let f = { "type": "Polygon", "coordinates": [outputCoords] };
  303. let result = turf.buffer(f, 1 / 99999, {
  304. units: "kilometers",
  305. });
  306. let positions = [];
  307. const twoDArray = result.geometry.coordinates[0];
  308. const oneDArray = twoDArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
  309. positions = oneDArray;
  310. if (this.isArray2D(oneDArray)) {
  311. const oneDArray2 = oneDArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
  312. positions = oneDArray2;
  313. } else {
  314. }
  315. query_click_by_iserver.entities.add({
  316. polygon: {
  317. // 获取指定属性(positions,holes(图形内需要挖空的区域))
  318. hierarchy: {
  319. positions: Cesium.Cartesian3.fromDegreesArray(positions)
  320. },
  321. // 边框
  322. outline: false,
  323. // 边框颜色
  324. outlineColor: Cesium.Color.RED,
  325. // 边框尺寸
  326. outlineWidth: 10,
  327. // 填充的颜色,withAlpha透明度
  328. material: Cesium.Color.RED,
  329. // 是否被提供的材质填充
  330. fill: true,
  331. // 恒定高度
  332. height: 1.1,
  333. // 显示在距相机的距离处的属性,多少区间内是可以显示的
  334. // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(1000, 10000000),
  335. // 是否显示
  336. show: true,
  337. // 顺序,仅当`clampToGround`为true并且支持地形上的折线时才有效。
  338. zIndex: 10
  339. }
  340. });
  341. },
  342. convertCoordinates(coordArray) {
  343. return coordArray.map(coord => [coord.x, coord.y]);
  344. },
  345. calcIserverURI(url) {
  346. let uriArr = url.split("/");
  347. uriArr[5] = uriArr[5].replace("map-", "data-");
  348. uriArr[7] = "data";
  349. uriArr[8] = "featureResults.rjson?returnContent=true";
  350. return uriArr.join("/");
  351. },
  352. multiPolygonToPolygons(multiPolygon) {
  353. const polygons = [];
  354. multiPolygon.coordinates.forEach(polygonCoordinates => {
  355. polygons.push({
  356. type: 'Polygon',
  357. coordinates: polygonCoordinates
  358. });
  359. });
  360. return polygons;
  361. },
  362. clear_data() {
  363. const that = this;
  364. store.state.query_pick_last_pane = null;
  365. store.state.query_pick_pane = [];
  366. // 图标
  367. var entities = manager_multi_level_query.entities.values;
  368. for (var i = entities.length - 1; i >= 0; i--) {
  369. manager_multi_level_query.entities.remove(entities[i]);
  370. }
  371. // 矢量
  372. manager_multi_level_vector.removeAll();
  373. // for (let index = 0; index < manager_multi_level_vector._primitives.length; index++) {
  374. // const element = manager_multi_level_vector._primitives[index];
  375. // console.log('element: ', element);
  376. // viewer.scene.primitives.remove(element);
  377. // }
  378. this.remove_query_click_by_iserver();
  379. },
  380. add_viewer_for_vector(geojson, data) {
  381. const twoDArray = geojson.coordinates[0];
  382. const oneDArray = twoDArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
  383. let polygon = new Cesium.GeometryInstance({
  384. // id: JSON.stringify(obj),
  385. geometry: new Cesium.PolygonGeometry({
  386. minimum: new Cesium.Cartesian3(0, 0, 0),
  387. maximum: new Cesium.Cartesian3(100000, 100000, 100000),
  388. polygonHierarchy: new Cesium.PolygonHierarchy(
  389. Cesium.Cartesian3.fromDegreesArray(oneDArray)
  390. ),
  391. height: 1,
  392. // extrudedHeight: 10,
  393. })
  394. })
  395. let addPolygonGeometry = new Cesium.Primitive({
  396. geometryInstances: polygon,
  397. appearance: new Cesium.EllipsoidSurfaceAppearance({
  398. material: Cesium.Material.fromType('Color', {
  399. color: Cesium.Color.fromRandom({
  400. alpha: 0.8
  401. })
  402. })
  403. }),
  404. show: true,
  405. })
  406. manager_multi_level_vector.add(addPolygonGeometry)
  407. },
  408. draw_vector(geojson, data) {
  409. // viewer.dataSources.add(Cesium.GeoJsonDataSource.load(geojson, {
  410. // stroke: Cesium.Color.HOTPINK,
  411. // fill: Cesium.Color.PINK,
  412. // strokeWidth: 3,
  413. // markerSymbol: '?'
  414. // }));
  415. const that = this;
  416. if (geojson.type == 'MultiPolygon') {
  417. let polygons = that.multiPolygonToPolygons(geojson);
  418. polygons.forEach((res) => {
  419. that.add_viewer_for_vector(res, data);
  420. })
  421. } else {
  422. that.add_viewer_for_vector(geojson, data);
  423. }
  424. },
  425. remove_query_click_by_iserver() {
  426. for (var i = 0; i < 10; i++) {
  427. query_click_by_iserver.entities.values.forEach((res) => {
  428. query_click_by_iserver.entities.remove(res);
  429. })
  430. }
  431. },
  432. isArray2D(arr) {
  433. // 首先检查arr是否是数组
  434. if (!Array.isArray(arr)) {
  435. return false;
  436. }
  437. // 检查数组中的每个元素是否也是数组
  438. for (let i = 0; i < arr.length; i++) {
  439. if (!Array.isArray(arr[i])) {
  440. return false;
  441. }
  442. }
  443. // 如果所有元素都是数组,那么arr是二维数组
  444. return true;
  445. },
  446. },
  447. beforeCreate() { }, //生命周期 - 创建之前
  448. created() { }, //生命周期 - 创建完成(可以访问当前this实例)
  449. beforeMount() { }, //生命周期 - 挂载之前
  450. mounted() {
  451. const that = this;
  452. this.$nextTick(() => {
  453. that.handler_multi_level_query = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  454. manager_multi_level_query = new Cesium.CustomDataSource("manager_multi_level_query");
  455. viewer.dataSources.add(manager_multi_level_query);
  456. manager_multi_level_vector = new Cesium.PrimitiveCollection();
  457. manager_multi_level_vector.destroyPrimitives = false;
  458. viewer.scene.primitives.add(manager_multi_level_vector);
  459. pick_entity = new Cesium.CustomDataSource("pick_entity");
  460. viewer.dataSources.add(pick_entity);
  461. query_click_by_iserver = new Cesium.CustomDataSource("query_click_by_iserver");
  462. viewer.dataSources.add(query_click_by_iserver);
  463. })
  464. }, //生命周期 - 挂在完成
  465. beforeUpdate() { }, //生命周期 - 更新之前
  466. updated() { }, //生命周期 - 更新之后
  467. beforeDestroy() { }, //生命周期 - 销毁之前
  468. destroy() { },//生命周期 - 销毁完成
  469. activated() { }, //若组件实例是 <KeepAlive> 缓存树的一部分,当组件被插入到 DOM 中时调用。
  470. deactivated() { } //若组件实例是 <KeepAlive> 缓存树的一部分,当组件从 DOM 中被移除时调用。
  471. };
  472. </script>
  473. <style lang="scss">
  474. .el-collapse {
  475. // width: 95%;
  476. border: none;
  477. background-color: transparent !important;
  478. }
  479. .el-scrollbar {
  480. border: 1px solid #0f7ac8 !important;
  481. // padding: 0 10px;
  482. }
  483. .el-collapse-item__header {
  484. // border-bottom: 1px solid rgba(102, 126, 143, 0.747);
  485. background-color: transparent !important;
  486. color: rgb(217, 237, 254) !important;
  487. border-color: transparent !important;
  488. }
  489. .el-collapse-item__wrap {
  490. background-color: transparent !important;
  491. border-color: transparent !important;
  492. }
  493. .el-collapse-item__content {
  494. // background-color: rgba(255, 192, 203, 0.425) !important;
  495. background-color: transparent !important;
  496. color: rgb(217, 237, 254) !important;
  497. }
  498. </style>
  499. <style lang="scss" scoped>
  500. .echart {
  501. width: 300px;
  502. height: 420px;
  503. }
  504. .echart1 {
  505. height: 280px;
  506. }
  507. .multi_level_query_table {
  508. position: absolute;
  509. top: 7rem;
  510. width: 19rem;
  511. }
  512. /* 去掉tabs标签栏下的下划线 */
  513. ::v-deep .el-tabs__nav-wrap::after {
  514. position: static !important;
  515. /* background-color: #fff; */
  516. }
  517. /* 下划线切换高亮 */
  518. ::v-deep .el-tabs__active-bar {
  519. background-color: #30fdff;
  520. }
  521. ::v-deep .el-collapse-item__header {
  522. color: #64daff !important;
  523. font-weight: 600;
  524. }
  525. .el-tab-pane {
  526. height: 33rem;
  527. overflow: auto;
  528. }
  529. .list_vector_multi {
  530. background-image: url("/static/images/ghzc/内容框.png");
  531. width: 18rem;
  532. border-top: 1px solid #CCC;
  533. font-size: 14px;
  534. padding: 0.1rem 0rem 0.1rem 0rem;
  535. border-left: 1px solid #CCC;
  536. border-right: 1px solid #CCC;
  537. // border-bottom:1px solid #CCC ;
  538. }
  539. .list_vector_multi:last-child {
  540. border-bottom: 1px solid #CCC;
  541. }
  542. .filed_box {
  543. display: inline-block;
  544. }
  545. </style>