From e5e65bb50cbfb973f98191993ab559767eff7a53 Mon Sep 17 00:00:00 2001 From: suerprisePlus <15810472099@163.com> Date: 星期二, 30 七月 2024 17:06:34 +0800 Subject: [PATCH] 页面添加(知识图谱,数据统计,数据分析,站点管理) --- src/views/visual/mapView/attributeInfo.vue | 171 +++ src/components/Tool/Popup.vue | 2 src/views/visual/mapView/location.vue | 2 src/utils/mapServer/kgServer.js | 9 public/glb/LJX.glb | 0 src/assets/js/mapSdk/mapConfig.js | 35 public/glb/SNG.glb | 0 public/glb/ZB.glb | 0 src/assets/js/mapSdk/index.js | 29 src/views/visual/mapLayer/index.vue | 460 +++++++++ public/glb/GLKG.glb | 0 src/components/mapOl/index.vue | 193 ++++ public/glb/RDQ.glb | 0 public/glb/XB.glb | 0 src/api/mapView/map.js | 59 + public/config/config.js | 35 public/glb/GGG.glb | 0 src/store/modules/mapLayers.js | 31 src/store/getters.js | 2 src/assets/js/configTools.js | 21 public/glb/BYQ.glb | 0 src/views/visual/mapView/lineRoaming.vue | 118 ++ public/glb/QT.glb | 0 src/assets/js/mapSdk/mapData.js | 133 ++ src/store/index.js | 5 src/views/visual/mapView/dataStatistics.vue | 157 +++ src/views/visual/atlas/index.vue | 363 +++++++ public/glb/DLQ.glb | 0 src/assets/js/mapSdk/mapServe.js | 169 +++ src/views/visual/mapView/layerManager.vue | 105 ++ src/views/visual/mapView/index.vue | 67 + src/views/visual/analysis/index.vue | 197 ++++ package.json | 12 src/views/visual/mapView/undergroundMode.vue | 116 ++ public/glb/BDZ.glb | 0 src/views/visual/mapView/dataAnalysis.vue | 44 public/glb/PDS.glb | 0 src/views/dataManager/siteInfo/index.vue | 285 +++++ src/assets/js/mapSdk/menuManager.js | 3 39 files changed, 2,766 insertions(+), 57 deletions(-) diff --git a/package.json b/package.json index 485ab99..52ec330 100644 --- a/package.json +++ b/package.json @@ -36,14 +36,16 @@ "url": "https://gitee.com/y_project/RuoYi-Vue.git" }, "dependencies": { + "@antv/g6": "^4.8.19", "@easydarwin/easywasmplayer": "^4.0.7", "@jiaminghi/data-view": "^2.10.0", "@riophae/vue-treeselect": "0.4.0", + "@turf/turf": "^7.0.0", "axios": "0.24.0", "clipboard": "2.0.8", "codemirror": "^5.65.2", - "core-js": "3.25.3", - "echarts": "5.4.0", + "core-js": "^3.25.3", + "echarts": "^5.4.0", "element-china-area-data": "^4.1.1", "element-ui": "2.15.10", "file-saver": "2.0.5", @@ -58,11 +60,14 @@ "moment": "^2.29.4", "mqtt": "^4.3.3", "nprogress": "0.2.0", + "ol": "^6.15.1", "quill": "1.3.7", + "relation-graph": "^2.2.3", "screenfull": "5.0.2", "script-loader": "^0.7.2", "sortablejs": "1.10.2", "sql-formatter": "^4.0.2", + "terraformer-wkt-parser": "^1.2.1", "three": "^0.157.0", "vue": "2.6.12", "vue-clipboard2": "^0.3.3", @@ -76,7 +81,8 @@ "vue-router": "3.4.9", "vue-seamless-scroll": "^1.1.23", "vuedraggable": "2.24.3", - "vuex": "3.6.0" + "vuex": "3.6.0", + "xlsx": "^0.16.0" }, "devDependencies": { "@vue/cli-plugin-babel": "4.4.6", diff --git a/public/config/config.js b/public/config/config.js index e917262..0abac97 100644 --- a/public/config/config.js +++ b/public/config/config.js @@ -1,8 +1,39 @@ console.log(location); const host = location.origin; +const isWeb = false; +var isUrl = isWeb ? "103.135.160.14" : "192.168.11.24"; +// api绔彛 +const apiHost = isWeb ? isUrl + "" : isUrl + ":12316"; +// 閰嶇綉绔彛 +const peiWangHost = isWeb ? isUrl + "" : isUrl + ":8101"; +// GeoServer绔彛 +const geoHost = isWeb ? isUrl + "" : isUrl + ":9055"; +// {host}鏇挎崲 +const iisHost = isWeb ? isUrl + ":9036" : "localhost:80"; +// 鐭ヨ瘑鍥捐氨绔彛 +const kgHost = isWeb ? isUrl + ":9036" : isUrl + ":8080"; +// 鏁版嵁鍒嗘瀽绔彛 +const pyHost = isWeb ? isUrl + ":9036" : isUrl + ":8000"; +//閰嶇疆 const config = { - apiServices: "http://192.168.11.24:12316/server/", + // server鏈嶅姟 + apiServices: "http://" + apiHost + "/server/", + // 鐭ヨ瘑鍥捐氨鏈嶅姟 + kgServices: "http://" + kgHost, + // 閰嶇綉鏈嶅姟 + peiWangServices: "http://" + peiWangHost + "/peiwang/", + //鏁版嵁鍒嗘瀽鎺ュ彛 + pyServices: "http://" + pyHost + "/py", imageUrl: "", - sdkImg: host+"/visual/CimSDK/" + // sdk鏄剧ず + sdkImg: host + "/visual/CimSDK/", + // 澶╁湴鍥� + tdToken: "94a34772eb88317fcbf8428e10448561", + // geoServer鏈嶅姟 + geoServer: { + url: "http://" + geoHost + "/geoserver/sxpw", + wms: "/wms", + wfs: "" + } }; diff --git a/public/glb/BDZ.glb b/public/glb/BDZ.glb new file mode 100644 index 0000000..8034fe0 --- /dev/null +++ b/public/glb/BDZ.glb Binary files differ diff --git a/public/glb/BYQ.glb b/public/glb/BYQ.glb new file mode 100644 index 0000000..21f728e --- /dev/null +++ b/public/glb/BYQ.glb Binary files differ diff --git a/public/glb/DLQ.glb b/public/glb/DLQ.glb new file mode 100644 index 0000000..604fca5 --- /dev/null +++ b/public/glb/DLQ.glb Binary files differ diff --git a/public/glb/GGG.glb b/public/glb/GGG.glb new file mode 100644 index 0000000..dac59dc --- /dev/null +++ b/public/glb/GGG.glb Binary files differ diff --git a/public/glb/GLKG.glb b/public/glb/GLKG.glb new file mode 100644 index 0000000..0511799 --- /dev/null +++ b/public/glb/GLKG.glb Binary files differ diff --git a/public/glb/LJX.glb b/public/glb/LJX.glb new file mode 100644 index 0000000..5b8c4dc --- /dev/null +++ b/public/glb/LJX.glb Binary files differ diff --git a/public/glb/PDS.glb b/public/glb/PDS.glb new file mode 100644 index 0000000..c70d5e6 --- /dev/null +++ b/public/glb/PDS.glb Binary files differ diff --git a/public/glb/QT.glb b/public/glb/QT.glb new file mode 100644 index 0000000..49138b2 --- /dev/null +++ b/public/glb/QT.glb Binary files differ diff --git a/public/glb/RDQ.glb b/public/glb/RDQ.glb new file mode 100644 index 0000000..988fd1a --- /dev/null +++ b/public/glb/RDQ.glb Binary files differ diff --git a/public/glb/SNG.glb b/public/glb/SNG.glb new file mode 100644 index 0000000..4e911f4 --- /dev/null +++ b/public/glb/SNG.glb Binary files differ diff --git a/public/glb/XB.glb b/public/glb/XB.glb new file mode 100644 index 0000000..c10436e --- /dev/null +++ b/public/glb/XB.glb Binary files differ diff --git a/public/glb/ZB.glb b/public/glb/ZB.glb new file mode 100644 index 0000000..c10436e --- /dev/null +++ b/public/glb/ZB.glb Binary files differ diff --git a/src/api/mapView/map.js b/src/api/mapView/map.js index 72b9793..8125790 100644 --- a/src/api/mapView/map.js +++ b/src/api/mapView/map.js @@ -1,6 +1,63 @@ -import mapServer from '../../utils/mapServer/mapServer'; +import mapServer from '@/utils/mapServer/mapServer'; +import kgServer from '@/utils/mapServer/kgServer'; //閰嶇綉鎺ュ彛 => 鏌ヨ鎵�鏈� export function zhangzitou_selectAllLine(params) { return mapServer.get('/zhangzitou/selectAllLine', { params: params }); } +//鍥惧眰绠$悊 => 鏌ヨ鎵�鏈� +export function layer_selectAll(params) { + return mapServer.get('/layer/selectAll', { params: params }); +} +//鍥惧眰绠$悊 => 鏂板鍥惧眰 +export function layer_insert(params) { + return mapServer.post('/layer/insert', params); +} +//鍥惧眰绠$悊=> 鍒犻櫎鍥惧眰 +export function layer_delete(params) { + return mapServer.get('/layer/delete', { params: params }); +} + +//鍥惧眰绠$悊=> 鍒犻櫎鍥惧眰 +export function layer_updates(params) { + return mapServer.post('/layer/updates', params); +} +//鍥惧眰绠$悊=> 鏇存柊涓�鏉� +export function layer_update(params) { + return mapServer.post('/layer/update', params); +} + +//閰嶇綉鎺ュ彛 => 鏌ヨ鎵�鏈� +export function zhangzitou_selectAll(params) { + return mapServer.get('/zhangzitou/selectAll', { params: params }); +} +//鍥捐氨鏌ヨ鎺ュ彛 +export function kg_getGraph(params) { + return kgServer.post('/kg/getGraph', params); +} +//鍥捐氨鏌ヨ鎺ュ彛 +export function kg_queryGraphResult(params) { + return kgServer.post('/kg/queryGraphResult', params); +} + +//閰嶇綉鎺ュ彛 => 鏁版嵁缁熻 +export function zhangzitou_selectInfos(params) { + return mapServer.get('/zhangzitou/selectInfos', { params: params }); +} +//閰嶇綉鎺ュ彛 => 鏁版嵁缁熻=>绾胯矾 +export function zhangzitou_deleteZhangzitouEntitys(params) { + return mapServer.get('/zhangzitou/deleteZhangzitouEntitys', { params: params }); +} + +//閰嶇綉鎺ュ彛 => 绔欑偣鏂板 +export function zhangzitou_insertZhangzitouEntity(params) { + return mapServer.post('/zhangzitou/insertZhangzitouEntity', params); +} +//閰嶇綉鎺ュ彛 => 淇敼绔欑偣 +export function zhangzitou_updateZhangzitouEntity(params) { + return mapServer.post('/zhangzitou/updateZhangzitouEntity', params); +} +// //閰嶇綉鎺ュ彛 => 鍒犻櫎绔欑偣 +// export function zhangzitou_deleteZhangzitouEntitys(params) { +// return mapServer.get('/zhangzitou/deleteZhangzitouEntitys', { params: params } ); +// } \ No newline at end of file diff --git a/src/assets/js/configTools.js b/src/assets/js/configTools.js index 37942cd..994795a 100644 --- a/src/assets/js/configTools.js +++ b/src/assets/js/configTools.js @@ -20,6 +20,25 @@ }, add0(m) { return m < 10 ? '0' + m : m; - }, + }, + //JSON鐢熸垚鐩綍鏍� + getTreeData(res) { + let cloneData = JSON.parse(JSON.stringify(res)); // 瀵规簮鏁版嵁娣卞害鍏嬮殕 + return cloneData.filter((father) => { + // 寰幆鎵�鏈夐」 + let branchArr = cloneData.filter((child) => father.id == child.pid); + if (branchArr.length > 0) { + branchArr.sort(function (a, b) { + return a.orderNum - b.orderNum; + }); + } + + branchArr.length > 0 ? (father.children = branchArr) : ''; // 缁欑埗绾ф坊鍔犱竴涓猚hildren灞炴�э紝骞惰祴鍊� + // 灞炰簬鍚屼竴瀵硅薄闂锛屼緥濡傦細浠� a=b銆乧=1 锛岀劧鍚庡啀浠� b.c=c 锛� 閭d箞 a.c=b.c=c=1 锛涘悓鐞嗭紝鍚庣画浠� c.d=2 ,閭d箞 a.c.d 涔熸槸=2锛� + // 鐢辨寰幆澶氭鍚庯紝灏辫兘褰㈡垚鐩稿簲鐨勬爲褰㈡暟鎹粨鏋� + return father.pid == 0; // 杩斿洖涓�绾ц彍鍗� + }); + }, + }; export default configTools; diff --git a/src/assets/js/mapSdk/index.js b/src/assets/js/mapSdk/index.js index 6980051..bcb21b0 100644 --- a/src/assets/js/mapSdk/index.js +++ b/src/assets/js/mapSdk/index.js @@ -1,3 +1,7 @@ +import mapConfig from './mapConfig'; +import mapData from './mapData'; +import mapServer from './mapServe'; + const mapInit = { Init() { window.earthCtrl = new SmartEarth.EarthCtrl('sdkContainer', { @@ -7,9 +11,32 @@ printLog: false, // sceneMode: SmartEarth.Cesium.SceneMode.SCENE2D }); + // 鍒濆鍖朇esium window.Cesium = SmartEarth.Cesium; + // 鍒濆鍖朧iewer window.Viewer = earthCtrl.viewer; - Viewer.scene.globe.baseColor = Cesium.Color.fromCssColorString('#A9A9A9'); //璁剧疆鍦扮悆棰滆壊 + //璁剧疆鍦扮悆棰滆壊 + Viewer.scene.globe.baseColor = Cesium.Color.fromCssColorString('#A9A9A9'); + // 榛樿璁剧疆搴曞浘 + this.addImageLayer(); + }, + addImageLayer() { + const baseLayer = mapData.baseLayer; + // 娣诲姞澶╁湴鍥惧簳鍥� + mapServer.addLayer({ + serveType: 'tdMap', + url: baseLayer.sUrl + baseLayer.vecLayer + baseLayer.lUrl, + }); + // 娣诲姞澶╁湴鍥炬爣娉� + mapServer.addLayer({ + serveType: 'tdMap', + url: baseLayer.sUrl + baseLayer.cvaLayer + baseLayer.lUrl, + }); + // 鍒濆鍖栬瑙� + this.setdefaultPerspective(); + }, + setdefaultPerspective() { + mapConfig.sertCameraTo(mapData.defaultPerspective); }, }; export default mapInit; diff --git a/src/assets/js/mapSdk/mapConfig.js b/src/assets/js/mapSdk/mapConfig.js new file mode 100644 index 0000000..b558605 --- /dev/null +++ b/src/assets/js/mapSdk/mapConfig.js @@ -0,0 +1,35 @@ +import WKT from 'terraformer-wkt-parser'; +const mapConfig = { + sertCameraTo(res) { + earthCtrl.camera.jumpTo({ + destination: { + x: res.x, + y: res.y, + z: res.z, + }, + }); + }, + userSceneFlyTo(res){ + const options = { + duration: 2, + offset: new SmartEarth.Cesium.HeadingPitchRange(1.0, -0.3, 1000) + }; + earthCtrl.userScene.flyTo(res,options); + }, + getModelMatrix(res) { + var headingPitchRoll = new Cesium.HeadingPitchRoll(res.heading, res.pitch, res.roll); + var position = Cesium.Cartesian3.fromDegrees(res.longitude, res.latitude, res.altitude); + var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame( + position, headingPitchRoll, Cesium.Ellipsoid.WGS84, + Cesium.Transforms.eastNorthUpToFixedFrame, + new Cesium.Matrix4()); + return modelMatrix; + }, + getWKTParse(res){ + return WKT.parse(res) + }, + getWKTConvert(res){ + return WKT.convert(res) + } +}; +export default mapConfig; \ No newline at end of file diff --git a/src/assets/js/mapSdk/mapData.js b/src/assets/js/mapSdk/mapData.js index 81e940f..2b2db2f 100644 --- a/src/assets/js/mapSdk/mapData.js +++ b/src/assets/js/mapSdk/mapData.js @@ -1,3 +1,5 @@ +// import { label } from 'three/examples/jsm/nodes/Nodes.js'; + const mapData = { menuData: [ { @@ -73,13 +75,13 @@ { id: 's6', name: '瀹氫綅', - children:[ + children: [ { - id:'a1', - name:'鍧愭爣瀹氫綅', + id: 'a1', + name: '鍧愭爣瀹氫綅', pid: 's6', - } - ] + }, + ], }, { id: 's7', @@ -147,7 +149,7 @@ pid: 's8', }, { - id: 'a6', + id: 'a5', name: '娓呴櫎', pid: 's8', }, @@ -159,7 +161,7 @@ children: [ { id: 'a1', - name: '鍦颁笅妯″瀷', + name: '鍦颁笅妯″紡', pid: 's9', }, { @@ -170,5 +172,122 @@ ], }, ], + // 榛樿搴曞浘 + baseLayer: { + sUrl: 'http://t0.tianditu.gov.cn/DataServer?T=', + lUrl: '&x={x}&y={y}&l={z}&tk=', + vecLayer: 'vec_w', + cvaLayer: 'cva_w', + }, + // 榛樿瑙嗚 + defaultPerspective: { + x: -1935239.1689147458, + y: 4653957.816261454, + z: 3900586.9686804516, + }, + // 鍥惧眰绠$悊 + layerData: { + layerOption: [ + { + value: '1', + label: '鐩綍', + }, + { + value: '2', + label: '鍥惧眰', + }, + ], + sourceOption: [ + { + value: 'Tileset', + label: 'Tileset', + }, + { + value: 'WMS', + label: 'WMS', + }, + { + value: 'TMS', + label: 'TMS', + }, + { + value: 'GEOJSON', + label: 'GEOJSON', + }, + { + value: 'WFS', + label: 'WFS', + }, + ], + dataOption: [ + { value: '鏉嗗', label: '鏉嗗' }, + { + value: '閰嶇綉绠�', + label: '閰嶇綉绠�', + }, + { + value: '鐜綉鏌�', + label: '鐜綉鏌�', + }, + { + value: 'HW', + label: 'HW', + }, + { + value: 'KG', + label: 'KG', + }, + { + value: 'PD', + label: 'PD', + }, + { + value: 'XB', + label: 'XB', + }, + { + value: 'ZB', + label: 'ZB', + }, + { + value: '鍙樺帇鍣�', + label: '鍙樺帇鍣�', + }, + { + value: '鍙樼數绔�', + label: '鍙樼數绔�', + }, + { + value: '鎸囩ず鍣�', + label: '鎸囩ず鍣�', + }, + { + value: '鍏朵粬', + label: '鍏朵粬', + }, + ], + }, + // 鏁版嵁缁熻 + dataStatistics: { + BDZ: '鍙樼數绔�', + BYQ: '鍙樺帇鍣�', + DLQ: '鏂矾鍣�', + GT: '鏉嗗', + GGG: '閽㈢鏉�', + GLKG: '闅旂寮�鍏�', + LJX: '杩炴帴绾�', + PD: '閰嶇數瀹�', + RDQ: '鐔旀柇鍣�', + SNG: '姘存偿鏉�', + XB: '绠卞彉', + HW: '鐜綉鏌�', + DLZJJT: '鐢电紗涓棿鎺ュご', + ZB: 'ZB', + KG: '寮�鍏�', + ZSQ: '鏁呴殰鎸囩ず鍣�', + PDS: 'PDS', + + }, + }; export default mapData; diff --git a/src/assets/js/mapSdk/mapServe.js b/src/assets/js/mapSdk/mapServe.js new file mode 100644 index 0000000..541dd94 --- /dev/null +++ b/src/assets/js/mapSdk/mapServe.js @@ -0,0 +1,169 @@ +import mapConfig from './mapConfig'; +import { zhangzitou_selectAll } from '@/api/mapView/map.js'; +import WKT from 'terraformer-wkt-parser'; +// 鏈嶅姟鍔犺浇 +const mapServer = { + serveType: null, + layerList: [], + addLayer(res) { + const obj = this.getLayerChecked(res); + if (obj) return; + this.serveType = res.serveType; + switch (this.serveType) { + case 'tdMap': + this.addTdLayer(res); + break; + case 'WMS': + this.addWMSLayer(res); + break; + case 'Tileset': + this.addTilesetLayer(res); + break; + case 'WFS': + this.addWFSLayer(res); + break; + } + }, + addWFSLayer(res) { + zhangzitou_selectAll({ + limit: 1000000, + page: 1, + }).then((response) => { + if (response.data.code != 200) return; + const pois = response.data.result.pois; + const cnName = res.cnName + '_' + res.id; + const modelLayer = new Cesium.PrimitiveCollection(); + modelLayer.name = cnName; + Viewer.scene.primitives.add(modelLayer); + pois.map((item) => { + var geom = WKT.parse(item.geom); + var style = { + longitude: geom.coordinates[0], + latitude: geom.coordinates[1], + altitude: 0, + heading: 0, + pitch: 0, + roll: 0, + }; + const modelMatrix = mapConfig.getModelMatrix(style); + const url = '/glb/' + item.type + '.glb'; + modelLayer.add( + Cesium.Model.fromGltf({ + id: item.id, + url: url, + scale: 1, + minimumPixelSize: 20, + maximumScale: 20, + modelMatrix: modelMatrix, + primitive: item, + }) + ); + }); + this.layerList.push({ + id: res.id, + name: cnName, + layer: modelLayer, + serveType: this.serveType, + }); + }); + }, + + addTdLayer(res) { + const url = res.url + config.tdToken; + Viewer.imageryLayers.addImageryProvider( + new Cesium.UrlTemplateImageryProvider({ + url: url, + }) + ); + }, + getLayerChecked(res) { + const obj = this.layerList.filter((item) => { + if (item.id == res.id) { + return item; + } + }); + const boolen = obj.length > 0 ? true : false; + return boolen; + }, + addWMSLayer(res) { + const serverUrl = config.geoServer; + const that = this; + var getFeatureInfoFormat = new Cesium.GetFeatureInfoFormat('html', null, function (html) { + that.getFeatureInfo(html); + }); + + const layer = new Cesium.WebMapServiceImageryProvider({ + url: serverUrl.url + serverUrl.wms, + layers: res.url, + getFeatureInfoParameters: { info_format: 'text/html' }, + enablePickFeatures: true, + getFeatureInfoFormats: [getFeatureInfoFormat], + parameters: { + transparent: true, + format: 'image/png', + srs: 'EPSG:4490', + styles: '', + cql_filter: '', + }, + tileWidth: 512, + tileHeight: 512, + }); + + const imageLayer = Viewer.imageryLayers.addImageryProvider(layer); + const cnName = res.cnName + '_' + res.id; + imageLayer.name = cnName; + imageLayer.id = res.id; + this.layerList.push({ + id: res.id, + name: cnName, + layer: imageLayer, + serveType: this.serveType, + }); + }, + addTilesetLayer(res) { + let url = res.url.indexOf('{host}') > -1 ? res.url.replace('{host}', iisHost) : res.url; + var height = 0; + if (res.bak) { + height = JSON.parse(res.bak).height; + } + var model = earthCtrl.factory.create3DTilesets({ + url: url, + option: { + height: height, + id: res.id, + }, + }); + const cnName = res.cnName + '_' + res.id; + model.item.readyPromise.then((item) => { + mapConfig.userSceneFlyTo(item); + this.layerList.push({ + id: res.id, + name: cnName, + layer: model, + serveType: this.serveType, + }); + }); + }, + setTilesetArgs() {}, + removeLayer(res) { + const cnName = res.cnName + '_' + res.id; + this.layerList.map((item, index) => { + if (cnName == item.name && res.id == item.id) { + if (item.serveType == 'WMS') { + Viewer.imageryLayers.remove(item.layer); + this.layerList.splice(index, 1); + } else if (item.serveType == 'Tileset') { + item.layer.deleteObject(); + this.layerList.splice(index, 1); + }else if (item.serveType == 'WFS') { + Viewer.scene.primitives.remove(item.layer) + this.layerList.splice(index, 1); + } + } + }); + }, + async getFeatureInfo(res) { + console.log(res); + }, +}; +export default mapServer; diff --git a/src/assets/js/mapSdk/menuManager.js b/src/assets/js/mapSdk/menuManager.js index caf3ce7..e2a46a0 100644 --- a/src/assets/js/mapSdk/menuManager.js +++ b/src/assets/js/mapSdk/menuManager.js @@ -1,3 +1,4 @@ + const menuManager = { pid: null, pointFly: null, @@ -190,7 +191,7 @@ return res.name; break; case 'a2': - return res.name; + earthCtrl.factory.createScreenshot(); break; default: return null; diff --git a/src/components/Tool/Popup.vue b/src/components/Tool/Popup.vue index 0bdab40..cd7981b 100644 --- a/src/components/Tool/Popup.vue +++ b/src/components/Tool/Popup.vue @@ -43,7 +43,7 @@ showBox: false, // 鏄惁鏄剧ず鍐呭 showContainer: true, - defaultMaxHeight: '400px', + defaultMaxHeight: '700px', }; }, directives: { diff --git a/src/components/mapOl/index.vue b/src/components/mapOl/index.vue new file mode 100644 index 0000000..6537e15 --- /dev/null +++ b/src/components/mapOl/index.vue @@ -0,0 +1,193 @@ +<template> + <div id="mapView" class="olBox"> + <div class="menuTool"> + <el-form :inline="true" :model="formInline" class="demo-form-inline"> + <el-form-item label="缁忓害:"> + {{ formInline.lon }} + </el-form-item> + <el-form-item label="绾害:"> + {{ formInline.lat }} + </el-form-item> + <el-form-item> + <el-button type="success" icon="el-icon-plus" @click="drowPoint"></el-button> + <el-button type="danger" icon="el-icon-delete" @click="clearDrawPoint"></el-button> + </el-form-item> + </el-form> + </div> + </div> +</template> + +<script> +import TileLayer from 'ol/layer/Tile'; +import XYZ from 'ol/source/XYZ'; +import Map from 'ol/Map'; +import View from 'ol/View'; +import { transform } from 'ol/proj'; +import VectorSource from 'ol/source/Vector'; +import { Vector as VectorLayer, Tile } from 'ol/layer'; +import { Draw } from 'ol/interaction'; +import Feature from 'ol/Feature'; +import { Circle as CircleStyle, Style, Fill, Stroke, Icon, Text } from 'ol/style'; +import { Point } from 'ol/geom'; +import ImageWMS from "ol/source/ImageWMS"; +import Image from "ol/layer/Image"; +import mapData from '@/assets/js/mapSdk/mapData.js'; +import mapConfig from '../../assets/js/mapSdk/mapConfig'; +import * as turf from '@turf/turf' +export default { + props: { + parentData: { + type: String, + default: '', + + } + }, + data() { + return { + mapol: null, + drawLayer: null, + formInline: { + lon: '', + lat: '' + } + } + }, + mounted() { + this.initOlMap(); + }, + methods: { + initOlMap() { + const baseLayer = mapData.baseLayer; + const vecUrl = baseLayer.sUrl + baseLayer.vecLayer + baseLayer.lUrl + var vectorLayer = new TileLayer({ + source: new XYZ({ + url: vecUrl + config.tdToken, + }), + }); + const cvaUrl = baseLayer.sUrl + baseLayer.cvaLayer + baseLayer.lUrl + var vectorLayer1 = new TileLayer({ + source: new XYZ({ + url: cvaUrl + config.tdToken, + }), + }); + this.mapol = new Map({ + target: 'mapView', + layers: [vectorLayer, vectorLayer1], + view: new View({ + center: transform([112.5545931210261, 37.86275646283009], 'EPSG:4326', 'EPSG:3857'), + zoom: 12, + projection: 'EPSG:3857', + }), + }); + + + var layer2 = new Image({ + name: "Wms_Layer", + source: new ImageWMS({ + crossOrigin: "anonymous", + url: config.geoServer.url + config.geoServer.wms, + params: { + FORMAT: "image/png", + VERSION: "1.1.1", + LAYERS: 'sxpw:sxdwx', + }, + }), + }); + this.mapol.addLayer(layer2); + if (this.parentData) { + const obj = mapConfig.getWKTParse(this.parentData) + this.formInline = { + lon: obj.coordinates[0], + lat: obj.coordinates[1], + } + this.addPointData(obj); + } + }, + addPointData(res) { + const coord = res.coordinates; + + const urlImg = config.sdkImg + 'Workers/image/mark.png'; + var geom = transform( + [parseFloat(coord[0]), parseFloat(coord[1])], + 'EPSG:4326', + 'EPSG:3857' + ); + var feature = new Feature({ + geometry: new Point(geom), + }); + feature.setStyle( + new Style({ + image: new Icon({ + scale: [0.8, 0.8], + src: urlImg + }), + + }) + ); + + const source = new VectorSource(); + source.addFeature(feature); + this.drawLayer = new VectorLayer(); + this.drawLayer.setSource(source); + this.mapol.addLayer(this.drawLayer); + this.setOlLocal(coord) + }, + setOlLocal(geom) { + this.mapol.getView().animate({ + center: transform(geom, 'EPSG:4326', 'EPSG:3857'), // 涓績鐐� + zoom: 18, // 缂╂斁绾у埆 + + }); + + }, + drowPoint() { + const source = new VectorSource({ wrapX: false }); + this.clearDrawPoint(); + this.drawLayer = new VectorLayer({ + source: source, + }); + this.mapol.addLayer(this.drawLayer); + this.draw = new Draw({ + source: source, // 鍜屽浘灞備娇鐢ㄥ悓涓�涓猻ource锛岀敾鐨勫浘褰㈠湪鍥惧眰涓婏紝鍥惧眰鍦ㄥ湴鍥句笂鍗冲彲灞曠ず + type: 'Point', // 鍙�夋嫨涓夎褰紝澶氳竟褰紝鍦嗗舰绛夊叿浣撹瀹樼綉demo + freehand: false, // 鐢婚�夎繕鏄偣閫� + }); + // 娣诲姞浜や簰 + this.mapol.addInteraction(this.draw); + this.draw.on('drawend', (e) => { + let feature = e.feature; + let geom = feature.getGeometry(); + var extent = geom.flatCoordinates; + var a1 = transform([extent[0], extent[1]], 'EPSG:3857', 'EPSG:4326'); + this.formInline.lon = parseFloat(a1[0]).toFixed(6); + this.formInline.lat = parseFloat(a1[1]).toFixed(6); + var point = turf.point([this.formInline.lon, this.formInline.lat]); + const gPoint= mapConfig.getWKTConvert(point.geometry) + this.$emit('childData', gPoint); + this.mapol.removeInteraction(this.draw); + }); + }, + clearDrawPoint() { + if (this.drawLayer) { + this.mapol.removeLayer(this.drawLayer); + } + }, + } +} +</script> + +<style lang="scss" scoped> +.olBox { + width: 100%; + height: 100%; + overflow: hidden; + margin: 0; + padding: 0; + + ::v-deep.ol-control { + display: none; + } + + .menuTool {} +} +</style> \ No newline at end of file diff --git a/src/store/getters.js b/src/store/getters.js index 8adb1b6..2b2da34 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -15,5 +15,7 @@ topbarRouters:state => state.permission.topbarRouters, defaultRoutes:state => state.permission.defaultRoutes, sidebarRouters:state => state.permission.sidebarRouters, + layerTree:state => state.mapLayers.layerTree, + defaultLayer:state => state.mapLayers.defaultLayer, } export default getters diff --git a/src/store/index.js b/src/store/index.js index 97aaef8..074c0c4 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -7,7 +7,7 @@ import permission from './modules/permission' import settings from './modules/settings' import getters from './getters' - +import mapLayers from './modules/mapLayers' Vue.use(Vuex) const store = new Vuex.Store({ @@ -17,7 +17,8 @@ user, tagsView, permission, - settings + settings, + mapLayers }, getters }) diff --git a/src/store/modules/mapLayers.js b/src/store/modules/mapLayers.js new file mode 100644 index 0000000..aa0a339 --- /dev/null +++ b/src/store/modules/mapLayers.js @@ -0,0 +1,31 @@ +import Cookies from 'js-cookie'; + +const state = { + layerTree: [], + defaultLayer: [], +}; + +const mutations = { + CHANGE_LAYERTREE: (state, res) => { + state.layerTree = res; + }, + CHANGE_DEFAULTLAYER: (state,res) => { + state.defaultLayer = res; + }, +}; + +const actions = { + changeLayerTree({ commit }, obj) { + commit('CHANGE_LAYERTREE', obj); + }, + changeDefaultLayer({ commit }, obj) { + commit('CHANGE_DEFAULTLAYER', obj); + }, +}; + +export default { + namespaced: true, + state, + mutations, + actions, +}; diff --git a/src/utils/mapServer/kgServer.js b/src/utils/mapServer/kgServer.js new file mode 100644 index 0000000..317db29 --- /dev/null +++ b/src/utils/mapServer/kgServer.js @@ -0,0 +1,9 @@ +import axios from "axios"; +const kgServer = axios.create({ + // axios涓姹傞厤缃湁baseURL閫夐」锛岃〃绀鸿姹俇RL鍏叡閮ㄥ垎 + baseURL: config.kgServices, + // 瓒呮椂 + timeout: -1 + }); + export default kgServer; + \ No newline at end of file diff --git a/src/views/dataManager/siteInfo/index.vue b/src/views/dataManager/siteInfo/index.vue new file mode 100644 index 0000000..0a97d27 --- /dev/null +++ b/src/views/dataManager/siteInfo/index.vue @@ -0,0 +1,285 @@ +<template> + <div class="siteInfo"> + <el-card> + <div class="infoSearch"> + <el-form :inline="true" :model="queryParams" class="demo-form-inline"> + <el-form-item label="鍚嶇О"> + <el-input size="small" v-model="queryParams.name" placeholder="璇疯緭鐐逛綅鍚嶇О..."></el-input> + </el-form-item> + </el-form> + <div> + <el-button size="small" plain type="primary" @click="setInfoQyery" icon="el-icon-search">鏌ヨ</el-button> + <el-button size="small" plain type="info" @click="setInfoRefresh" icon="el-icon-refresh">閲嶇疆</el-button> + <el-button size="small" plain type="success" @click="setInfoAdd" icon="el-icon-plus">娣诲姞</el-button> + <el-button size="small" plain type="danger" @click="setInfoDel" icon="el-icon-delete">鍒犻櫎</el-button> + </div> + </div> + </el-card> + + <el-card class="infoConTent"> + <div class="infoTable"> + <el-table :data="tableData" style="width: 100%" border height="calc(100% - 65px)" @selection-change="handleSelectionChange"> + <el-table-column type="selection" width="55" /> + <el-table-column align="center" type="index" label="搴忓彿" width="70px" /> + <el-table-column align="center" prop="id" v-if="false" /> + <el-table-column align="center" prop="name" label="鍚嶇О" /> + + <el-table-column align="center" prop="line" label="鐜嚎" /> + <el-table-column align="center" prop="type" label="绫诲瀷" :formatter="setInFoType" /> + <el-table-column align="center" prop="geom" label="浣嶇疆" /> + <el-table-column min-width="100" label="鎿嶄綔"> + <template slot-scope="scope"> + <el-button @click="setInfoEdit(scope.$index, scope.row)" type="warning" plain size="small">缂栬緫</el-button> + </template> + </el-table-column> + </el-table> + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageIndex" :limit.sync="queryParams.pageSize" @pagination="setInfoSearch" /> + </div> + </el-card> + <el-dialog width="30%" :title="dialogTitle" :before-close="outerClose" :visible.sync="dialogFlag"> + <el-form :model="editData"> + <el-form-item label="鍚嶇О" :label-width="formLabelWidth"> + <el-input v-model="editData.name" style="width: 100%" placeholder=""></el-input> + </el-form-item> + <el-form-item label="鐜嚎" :label-width="formLabelWidth"> + <el-input v-model="editData.line" style="width: 100%" placeholder=""></el-input> + </el-form-item> + <el-form-item label="绫诲瀷" :label-width="formLabelWidth"> + <el-select v-model="editData.type" style="width: 100%" placeholder=""> + <el-option v-for="item in siteOption" :key="item.value" :label="item.name" :value="item.val"></el-option> + </el-select> + </el-form-item> + <el-form-item label="浣嶇疆" :label-width="formLabelWidth"> + <div style="width: 100%"> + <el-input v-model="editData.geom" style="width: 92%" placeholder="" disabled=""></el-input> + <el-link style="float: right" @click="setInnerDialog"><i class="el-icon-plus"></i></el-link> + </div> + </el-form-item> + </el-form> + <el-dialog width="50%" title="鐐逛綅" :visible.sync="innerVisible" :before-close="innerClose" append-to-body> + <div style="height: 540px"> + <olMap v-if="innerVisible" @childData="childData" :parentData="parentData"></olMap> + </div> + </el-dialog> + <div slot="footer" class="dialog-footer"> + <el-button @click="outerClose">鍙� 娑�</el-button> + <el-button @click="submitOuter" type="primary">纭� 璁�</el-button> + </div> + </el-dialog> + </div> +</template> + +<script> +import { zhangzitou_selectAll, zhangzitou_insertZhangzitouEntity, zhangzitou_updateZhangzitouEntity, zhangzitou_deleteZhangzitouEntitys } from '@/api/mapView/map.js'; +import mapData from '@/assets/js/mapSdk/mapData'; +import olMap from '@/components/mapOl/index.vue'; +export default { + components: { + olMap, + }, + data() { + return { + total: 0, + queryParams: { + pageIndex: 1, + pageSize: 10, + name: '', + srid: 4326, + }, + formLabelWidth: '80px', + multipleSelection: [], + tableData: [], + editData: { + type: '', + }, + dialogTitle: null, + dialogFlag: false, + siteOption: [], + infoOption: null, + innerVisible: false, + parentData: null, + }; + }, + mounted() { + this.setInfoSearch(); + this.getInfoOption(); + }, + methods: { + setInFoType(row, column) { + var obj = row.type; + if (this.infoOption[obj]) { + return this.infoOption[obj]; + } + return obj; + }, + getInfoOption() { + this.infoOption = mapData.dataStatistics; + const option = []; + for (var key in this.infoOption) { + option.push({ + name: this.infoOption[key], + val: key, + }); + } + this.siteOption = option; + }, + setInfoQyery() { + this.queryParams.pageIndex = 1; + this.queryParams.pageSize = 10; + this.setInfoSearch(); + }, + setInfoSearch() { + zhangzitou_selectAll({ + limit: this.queryParams.pageSize, + page: this.queryParams.pageIndex, + name: this.queryParams.name, + }).then((response) => { + if (response.data.code != 200) return; + const valData = response.data.result; + this.tableData = valData.pois; + this.total = valData.total; + }); + }, + setInfoRefresh() { + this.queryParams = { + pageIndex: 1, + pageSize: 10, + name: '', + srid: 4326, + }; + this.setInfoSearch(); + }, + setInfoAdd() { + this.dialogTitle = '鏂板'; + this.editData.type = this.siteOption[0].val; + this.dialogFlag = true; + }, + setInfoDel() { + if (this.multipleSelection.length < 0) return; + const std = []; + for (var i in this.multipleSelection) { + std.push(this.multipleSelection[i].id); + } + zhangzitou_deleteZhangzitouEntitys({ ids: std.toString() }).then((response) => { + if (response.data.code != 200) { + return this.$message('鍒犻櫎澶辫触'); + } + this.$message({ + message: '鍒犻櫎鎴愬姛', + type: 'success', + }); + + this.setInfoQyery(); + }); + }, + setInfoEdit(index, row) { + this.dialogTitle = '淇敼'; + this.editData = { ...row }; + this.parentData = this.editData.geom; + this.dialogFlag = true; + }, + handleSelectionChange(res) { + this.multipleSelection = res; + }, + setInnerDialog() { + this.innerVisible = true; + }, + outerClose() { + this.dialogFlag = false; + this.parentData = null; + this.editData = { + type: '', + }; + }, + innerClose() { + this.innerVisible = false; + this.parentData = null; + }, + submitOuter() { + if (this.dialogTitle == '鏂板') { + this.outerInsert(); + } else { + this.outerEdit(); + } + this.dialogFlag = false; + }, + childData(res) { + this.editData.geom = res; + }, + outerInsert() { + const obj = { ...this.editData }; + zhangzitou_insertZhangzitouEntity(obj).then((response) => { + if (response.data.code != 200) { + return this.$message('鏂板澶辫触'); + } + this.$message({ + message: '鏂板鎴愬姛', + type: 'success', + }); + this.outerClose(); + this.setInfoRefresh(); + }); + }, + outerEdit() { + const obj = { ...this.editData }; + console.log(obj); + zhangzitou_updateZhangzitouEntity(obj).then((response) => { + if (response.data.code != 200) { + return this.$message('淇敼澶辫触'); + } + this.$message({ + message: '淇敼鎴愬姛', + type: 'success', + }); + this.outerClose(); + this.setInfoSearch(); + }); + }, + }, +}; +</script> + +<style lang="scss" scoped> +.siteInfo { + width: calc(100% - 20px); + height: calc(100% - 20px); + position: absolute; + margin: 10px; + border-radius: 5px; + display: flex; + flex-direction: column; + + .infoSearch { + display: flex; + justify-content: space-between; + align-items: center; + + ::v-deep.el-form-item { + margin: 0px; + } + } + + .infoConTent { + margin-top: 10px; + flex: 1; + position: relative; + + .infoTable { + width: calc(100% - 30px); + height: calc(100% - 36px); + position: absolute; + display: flex; + flex-direction: column; + } + } + + ::v-deep.el-divider--horizontal { + margin: 0px; + margin-bottom: 10px; + } + + ::v-deep.el-card__body { + padding: 15px; + } +} +</style> diff --git a/src/views/visual/analysis/index.vue b/src/views/visual/analysis/index.vue index 456942e..b6560cf 100644 --- a/src/views/visual/analysis/index.vue +++ b/src/views/visual/analysis/index.vue @@ -1,9 +1,160 @@ <template> - <div class="atlasBox"></div> + <div class="atlasBox" v-loading="gLoading"> + <el-form :inline="true" :model="formInline" class="demo-form-inline"> + <el-form-item label="涓婁紶鏁版嵁"> + <el-input :placeholder="placeholder" v-model="formInline.file"> + + <i slot="suffix" @click="onClickInputFile" class="el-input__icon el-icon-upload2"></i> + </el-input> + </el-form-item> + + <el-form-item> + <el-button type="primary" size="small" plain icon="el-icon-setting" @click="onSubmit">鍒� 鏋�</el-button> + <el-button type="info" size="small" plain icon="el-icon-refresh" @click="onRefresh">閲� 缃�</el-button> + </el-form-item> + </el-form> + + <input size="small" id="fromFile" type="file" style="display: none;" accept=".xlsx,.xls" + @change="onFileInputChange"></input> + <el-divider /> + <div class="atlasContnt"> + <el-table v-show="showTable" height=" calc(100% - 1px)" style=" width:100%" :data="tableData"> + <el-table-column v-for="(item, index) in tableDataHeader" :key="index" align="center" :prop="item.name + " :label="item.name"></el-table-column> + </el-table> + + <el-carousel v-show="!showTable" style="height: 100%;" :interval="5000" arrow="always"> + <el-carousel-item v-for="(item, key) in carouseList" :key="key"> + <el-image class="image" :src="item.src" :preview-src-list="[item.src]"> + </el-image> + </el-carousel-item> + </el-carousel> + + </div> + </div> </template> <script> -export default {}; +import XLSX from 'xlsx' +import $ from "jquery"; +export default { + data() { + return { + formInline: { + file: '' + }, + placeholder: "璇烽�夋嫨瑕佷笂浼犵殑鏁版嵁", + selectFileType: ".xlsx,.xls", + tableData: [], + tableDataHeader: [], + gLoading: false, + showTable: true, + carouseList: [], + } + }, + methods: { + onSubmit() { + var fs = document.getElementById("fromFile"); + if (fs.files.length == 0) { + this.$store.state.setLoading = false; + return this.$message("璇烽�夋嫨闇�瑕佷笂浼犵殑鏁版嵁鏂囦欢"); + } + this.gLoading = true; + var formFile = new FormData(); + var fileObj = fs.files[0] + formFile.append("file", fileObj); //鍔犲叆鏂囦欢瀵硅薄 + document.getElementById('fromFile').vlaue = ""; + this.formInline.file = '' + const that = this; + $.ajax( + config.pyServices + "/scatterplot", + { + type: 'POST', + data: formFile, + async: true, + cache: false, + contentType: false, + processData: false, + success: (rs) => { + that.showTable = false; + that.setShowImage(rs); + that.gLoading = false + + }, + error: (rs) => { + that.gLoading = false + }, + }) + }, + onRefresh() { + this.gLoading = false; + this.showTable = true; + this.carouseList = []; + this.tableData = []; + this.tableDataHeader = []; + document.getElementById('fromFile').vlaue = ""; + this.formInline.file = '' + }, + setShowImage(response) { + + const std = []; + for (var key in response) { + std.push({ + src: config.pyServices + '/image?file_name=' + response[key] + }) + } + this.carouseList = std + }, + onClickInputFile() { + document.getElementById('fromFile').click(); + }, + onFileInputChange(event) { + + var that = this + // 鎷垮彇鏂囦欢瀵硅薄 + let f = event.currentTarget.files[0] + + this.formInline.file = f.name + // 鐢‵ileReader鏉ヨ鍙� + let reader = new FileReader() + // 閲嶅啓FileReader涓婄殑readAsBinaryString鏂规硶 + FileReader.prototype.readAsBinaryString = (f) => { + let binary = '' + let wb // 璇诲彇瀹屾垚鐨勬暟鎹� + let outdata // 浣犻渶瑕佺殑鏁版嵁 + let reader = new FileReader() + + reader.onload = (e) => { + // 璇诲彇鎴怳int8Array锛屽啀杞崲涓篣nicode缂栫爜锛圲nicode鍗犱袱涓瓧鑺傦級 + let bytes = new Uint8Array(reader.result) + let length = bytes.byteLength + for (let i = 0; i < length; i++) { + binary += String.fromCharCode(bytes[i]) + } + + // 鎺ヤ笅鏉ュ氨鏄痻lsx浜嗭紝鍏蜂綋鍙湅api + wb = XLSX.read(binary, { + type: 'binary' + }) + outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) + var str = outdata[0]; + var std = []; + for (var key in str) { + + std.push({ name: key }) + + } + that.tableDataHeader = std + that.tableData = outdata + } + + reader.readAsArrayBuffer(f) + } + reader.readAsBinaryString(f) + + } + } +}; </script> <style lang="scss" scoped> @@ -13,6 +164,46 @@ position: absolute; margin: 10px; border-radius: 5px; - background: yellowgreen; + display: flex; + flex-direction: column; + + // background: yellowgreen; + ::v-deep.el-divider--horizontal { + margin: 0px; + margin-bottom: 10px; + } + + ::v-deep.el-form-item { + margin-bottom: 15px; + margin-top: 10px; + } + + .atlasContnt { + flex: 1; + + .image { + width: 100%; + height: 95%; + } + + ::v-deep.el-carousel__container { + height: 100%; + + } + + ::v-deep.el-carousel__button { + background: #409EFF !important + } + + // background: skyblue; + // ::v-deep.el-carousel__container { + // height: 100%; + + // } + + // ::v-deep.el-carousel__button { + // background: #409EFF !important + // } + } } </style> diff --git a/src/views/visual/atlas/index.vue b/src/views/visual/atlas/index.vue index a0e89d6..d890e9f 100644 --- a/src/views/visual/atlas/index.vue +++ b/src/views/visual/atlas/index.vue @@ -1,10 +1,335 @@ <template> - <div class="atlasBox"></div> + <div class="atlasBox"> + <div id="container" class="container" v-show="!showEcharts"> + <svg class="keywords" @mousemove="listener($event)"> + <a href="javascript:void(0)" v-for="(tag, index) in tags" :key="index" + @contextmenu="removeClick($event, tag)" @click="nodeClick(tag)"> + <text class="text" :x="tag.x" :y="tag.y" :font-size="20 * (600 / (600 - tag.z))" + :fill-opacity="(400 + tag.z) / 600" :fill="tag.color">{{ tag.text }}</text> + </a> + </svg> + </div> + <div class="graphicBox" v-show="showEcharts"> + <div class="konwReturn fl"> + <el-link @click="showEcharts = false"> + <i class="el-icon-d-arrow-left"></i> + </el-link> + 褰撳墠棰嗗煙:{{ targetName }} + </div> + <div id="graphicContent" v-loading="g_loading" class="graphicContent"> + <RelationGraph ref="graphRef" :options="graphOptions" :on-node-expand="onNodeExpand" + :on-node-collapse="onNodeCollapse"> + </RelationGraph> + </div> + </div> + </div> </template> <script> +import G6 from '@antv/g6'; +import { kg_getGraph, kg_queryGraphResult } from '@/api/mapView/map.js'; +import RelationGraph from 'relation-graph' export default { - + components: { RelationGraph }, + data() { + return { + width: null, + height: null, + tags: [], + showEcharts: false, + speedX: Math.PI / 360, + speedY: Math.PI / 360, + CX: 600, + CY: 300, + RADIUS: 200, + ZRADIUS: 200, + targetName: null, + // 鍥捐氨 + g_loading: true, + demoname: '---', + graphOptions: { + layout: + { + label: '涓績', + layoutName: 'tree', + layoutClassName: 'seeks-layout-center', + defaultJunctionPoint: 'border', + defaultNodeShape: 0, + defaultLineShape: 1, + from: 'left', + max_per_width: 300, + min_per_height: 40 + }, + defaultLineMarker: { + markerWidth: 12, + markerHeight: 12, + refX: 6, + refY: 6, + data: 'M2,2 L10,6 L2,10 L6,6 L2,2' + }, + moveToCenterWhenRefresh: false, + defaultExpandHolderPosition: 'right', + defaultNodeShape: 1, + defaultNodeWidth: 100, + defaultLineShape: 4, + defaultJunctionPoint: 'lr', + defaultNodeBorderWidth: 0, + defaultLineColor: 'rgba(0, 186, 189, 1)', + defaultNodeColor: 'rgba(0, 206, 209, 1)' + } + } + }, + + mounted() { + + // ; + this.setResizeStart(); + }, + methods: { + nodeClick(tag) { + this.showEcharts = true; + this.targetName = tag.text + this.g_loading = true + this.getGraphData(tag.text) + + }, + + getGraphData(name) { + + + + this.graphOptions.layout.max_per_width = this.width + kg_queryGraphResult( + { domain: name } + ).then(response => { + if (response.data.code != 200) return + this.g_loading = false; + const data = response.data.data + if (!this.width) { + this.width = document.getElementById('container').innerWidth; + } + const obj = data.node.filter(item => { + if (item.name == name) { + return item + } + }) + this.getGraphicNodes(data.node, data.relationship, obj) + }) + }, + onNodeCollapse(node, e) { + // const graphInstance = this.$refs.graphRef.getInstance(); + // graphInstance.doLayout(); + }, + // 閫氳繃onNodeExpand浜嬩欢鐩戝惉鑺傜偣鐨勫睍寮�浜嬩欢锛屽湪琚睍寮�鐨勬椂鍊欐湁閫夋嫨鐨勫幓浠庡悗鍙拌幏鍙栨暟鎹紝濡傛灉宸茬粡浠庡悗鍙板姞杞借繃鏁版嵁锛屽垯璁╁綋鍓嶅浘璋辨牴鎹綋鍓嶇殑鑺傜偣閲嶆柊甯冨眬 + onNodeExpand(node, e) { + const graphInstance = this.$refs.graphRef.getInstance(); + // 鏍规嵁鍏蜂綋鐨勪笟鍔¢渶瑕佸喅瀹氭槸鍚﹂渶瑕佷粠鍚庡彴鍔犺浇鏁版嵁 + if (!node.data.isNeedLoadDataFromRemoteServer) { + console.log('杩欎釜鑺傜偣鐨勫瓙鑺傜偣宸茬粡鍔犺浇杩囦簡'); + graphInstance.doLayout(); + return; + } + // 鍒ゆ柇鏄惁宸茬粡鍔ㄦ�佸姞杞芥暟鎹簡 + if (node.data.childrenLoaded) { + console.log('杩欎釜鑺傜偣鐨勫瓙鑺傜偣宸茬粡鍔犺浇杩囦簡'); + graphInstance.doLayout(); + return; + } + // this.g_loading = true; + node.data.childrenLoaded = true; + this.loadChildNodesFromRemoteServer(node); + }, + loadChildNodesFromRemoteServer(node) { + var graphInstance = this.$refs.graphRef.getInstance(); + graphInstance.doLayout(); + }, + getGraphicNodes(res, lines, obj) { + const std = []; + const ids = []; + + lines.filter(item => { + + if (ids.indexOf(item.sourceId) < 0) { + ids.push(item.sourceId) + } + if (obj && obj.length > 0) { + if (item.targetId == obj[0].uuid) { + ids.push(item.targetId) + } + } + + }) + + res.filter(item => { + var poi = false; + if (item.poi && item.poi == 1) { + poi = true; + } + + const expand = ids.indexOf(item.uuid) > -1 ? false : true + if (!expand) { + + std.push({ + // 'uuid': item.id ? item.id : new Date().getTime(), + 'id': item.uuid, + 'text': item.name, + // expandHolderPosition: 'right', + // expanded: true, + // data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }, + }) + } else { + std.push({ + // 'uuid': item.id ? item.id : new Date().getTime(), + 'id': item.uuid, + 'text': item.name, + // expandHolderPosition: 'right', + // expanded: false, + // data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }, + }) + } + + }) + this.getGraphicLines(std, lines) + }, + getGraphicLines(nodes, res) { + const std = []; + res.filter(item => { + std.push({ + "from": "" + item.sourceId + "", + "to": "" + item.targetId + "", + "text": "鍖呭惈", + }) + + }) + const json_data = { + 'rootId': 'a', + 'nodes': nodes, + 'lines': std + }; + this.setGraphic(json_data) + }, + setGraphic(res) { + + + + setTimeout(() => { + + this.$refs.graphRef.setJsonData(res, (graphInstance) => { + // 杩欎簺鍐欎笂褰撳浘璋卞垵濮嬪寲瀹屾垚鍚庨渶瑕佹墽琛岀殑浠g爜 + graphInstance.doLayout(); + }); + + }, 1000); + + + setTimeout(() => { + + var graphInstance = this.$refs.graphRef.getInstance(); + + }, 2000); + }, + removeClick() { }, + rotateX(speedX) { + var cos = Math.cos(speedX); + var sin = Math.sin(speedX); + for (let tag of this.tags) { + var y1 = (tag.y - this.CY) * cos - tag.z * sin + this.CY; + var z1 = tag.z * cos + (tag.y - this.CY) * sin; + tag.y = y1; + tag.z = z1; + } + }, + rotateY(speedY) { + var cos = Math.cos(speedY); + var sin = Math.sin(speedY); + for (let tag of this.tags) { + var x1 = (tag.x - this.CX) * cos - tag.z * sin + this.CX; + var z1 = tag.z * cos + (tag.x - this.CX) * sin; + tag.x = x1; + tag.z = z1; + } + }, + resizeWindow() { + if (this.showEcharts) return; + let height = document.getElementById('container').clientHeight; + let width = document.getElementById('container').clientWidth; + width = width * 0.85; + if (width > 1200) { + this.CX = width / 2; + } + height = height - 150; + this.CY = height / 2; + let radius = Math.min(this.CY, this.CX) / 2; + if (radius > 200) { + this.RADIUS = radius; + } + this.setCreateGraph(); + }, + setResizeStart() { + this.resizeWindow(); + window.addEventListener('resize', this.resizeWindow); + this.setCreateGraph(); + //浣跨悆寮�濮嬫棆杞� + const interval = setInterval(() => { + this.rotateX(this.speedX); + this.rotateY(this.speedY); + }, 17); + this.$once('hook:beforedestroy', () => { + interval && clearInterval(interval); + window.removeEventListener('resize', this.resizeWindow); + }); + }, + //鍥捐氨鍒濆鍖� + setCreateGraph() { + kg_getGraph({ + command: 0, + pageIndex: 1, + pageSize: 5000, + }).then((response) => { + if (response.data.code != 200) return; + + this.setGraphStart(response.data.data.nodeList); + }); + }, + listener(event) { + var x = event.clientX - this.CX; + var y = event.clientY - this.CY; + if (event.target.tagName == 'text') { + this.speedX = 0; + this.speedY = 0; + } else { + this.speedX = x * 0.00001 > 0 ? Math.min(this.RADIUS * 0.00002, x * 0.0001) : Math.max(-this.RADIUS * 0.00002, x * 0.0001); + this.speedY = y * 0.00001 > 0 ? Math.min(this.RADIUS * 0.00002, y * 0.0001) : Math.max(-this.RADIUS * 0.00002, y * 0.0001); + } + + // var val = document.getElementById("removeLabel").style.display; + // if (val == "none") { + // document.getElementById("removeLabel").style.top = event.clientY - 20 + 'px'; + // document.getElementById("removeLabel").style.left = event.clientX + 10 + 'px'; + // } + }, + setGraphStart(arr) { + const field = 'label'; + const obj = arr.filter((item, index) => { + return arr.findIndex((i) => i[field] === item[field]) === index; + }); + let tags = []; + const length = obj.length; + for (let i = 0; i < length; i++) { + let tag = {}; + let k = -1 + (2 * (i + 1) - 1) / length; + let a = Math.acos(k); + let b = a * Math.sqrt(length * Math.PI); + tag.text = obj[i].label; + (tag.id = obj[i].id), (tag.label = obj[i].label), (tag.x = this.CX + this.RADIUS * Math.sin(a) * Math.cos(b)); + tag.y = this.CY + this.RADIUS * Math.sin(a) * Math.sin(b); + tag.z = this.ZRADIUS * Math.cos(a); + tag.color = 'rgb(' + parseInt(Math.random() * 255) + ',' + parseInt(Math.random() * 255) + ',' + parseInt(Math.random() * 255) + ')'; + tags.push(tag); + } + this.tags = [].concat(tags); + }, + }, }; </script> @@ -15,6 +340,38 @@ position: absolute; margin: 10px; border-radius: 5px; - background: skyblue; + + // background: skyblue; + .container { + width: 100%; + height: 100%; + } + + .keywords { + width: 100%; + height: 100%; + } + + .keywords .text:hover { + font-size: 200%; + } + + .SVGBox { + width: 100%; + height: 100%; + } + + .graphicBox { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + + .graphicContent { + padding: 10px; + flex: 1; + + } + } } </style> diff --git a/src/views/visual/mapLayer/index.vue b/src/views/visual/mapLayer/index.vue new file mode 100644 index 0000000..f604cc4 --- /dev/null +++ b/src/views/visual/mapLayer/index.vue @@ -0,0 +1,460 @@ +<template> + <div class="layerBox"> + <div class="leftTree"> + <el-card class="treeCard"> + <div> + <el-input :placeholder="placeholderData" suffix-icon="el-icon-search" v-model="searchData"> + </el-input> + </div> + <div class="treeBox"> + <el-tree :data="treeData" node-key="id" :default-checked-keys="activeNodeId" + :default-expanded-keys="activeNodeId" :filter-node-method="filterNode" highlight-current + ref="tree" :props="defaultProps" @node-click="handleNodeClick"></el-tree> + </div> + </el-card> + </div> + <div class="rightContent"> + <el-card style="height: 100%;"> + <div class="contentMenu"> + <el-button icon="el-icon-plus" @click="setAddNode(true)">鏂板鍚岀骇</el-button> + <el-button icon="el-icon-plusde" :disabled="activeNode && activeNode.type != '1'" + @click="setAddNode(false)">鏂板瀛愮骇</el-button> + <el-button icon="el-icon-delete" @click="setDelNode">鍒犻櫎</el-button> + <el-button icon="el-icon-top" @click="setMoveUp">鍚戜笂绉诲姩</el-button> + <el-button icon="el-icon-bottom" @click="setMoveDown">鍚戜笅绉诲姩</el-button> + </div> + <el-divider /> + <el-form ref="formInline" :model="formInline" label-width="80px"> + <el-form-item label="鍥惧眰鍚嶇О : "> + <el-input v-model="formInline.cnName"></el-input> + </el-form-item> + <el-form-item label="鍥惧眰绫诲瀷 : "> + <el-select v-model="formInline.type" style="width: 100%;"> + <el-option v-for="item in layerOption" :key="item.value" :label="item.label" + :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="鏈嶅姟绫诲瀷 : " v-show="formInline.type == '2'"> + <el-select v-model="formInline.serveType" style="width: 100%;"> + <el-option v-for="item in sourceOption" :key="item.value" :label="item.label" + :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="鏈嶅姟鍦板潃 : " v-show="formInline.type == '2'"> + <el-input v-model="formInline.url"></el-input> + </el-form-item> + <el-form-item label="鏁版嵁绫诲瀷 : " v-show="formInline.type == '2'"> + <el-select v-model="formInline.dataType" style="width: 100%;"> + <el-option v-for="item in dataOption" :key="item.value" :label="item.label" + :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="鏄惁鏄剧ず : " v-show="formInline.type == '2'"> + <el-radio v-model="formInline.isShow" label="0">鍚�</el-radio> + <el-radio v-model="formInline.isShow" label="1">鏄�</el-radio> + </el-form-item> + <el-form-item label="澶囨敞 : "> + <el-input v-model="formInline.bak"></el-input> + </el-form-item> + <el-form-item> + <el-button type="primary" @click="onSubEdit">淇敼</el-button> + <el-button @click="onCanelEdit">閲嶇疆</el-button> + </el-form-item> + </el-form> + </el-card> + </div> + <el-dialog :title="appendTitle" :visible.sync="appendActive" width="30%"> + <el-form ref="appendFrom" :model="appendFrom" label-width="80px"> + <el-form-item label="鍥惧眰鍚嶇О : "> + <el-input v-model="appendFrom.cnName"></el-input> + </el-form-item> + <el-form-item label="鍥惧眰绫诲瀷 : "> + <el-select v-model="appendFrom.type" style="width: 100%;"> + <el-option v-for="item in layerOption" :key="item.value" :label="item.label" + :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="鏈嶅姟绫诲瀷 : " v-show="appendFrom.type == '2'"> + <el-select v-model="appendFrom.serveType" style="width: 100%;"> + <el-option v-for="item in sourceOption" :key="item.value" :label="item.label" + :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="鏈嶅姟鍦板潃 : " v-show="appendFrom.type == '2'"> + <el-input v-model="appendFrom.url"></el-input> + </el-form-item> + <el-form-item label="鏁版嵁绫诲瀷 : " v-show="appendFrom.type == '2'"> + <el-select v-model="appendFrom.dataType" style="width: 100%;"> + <el-option v-for="item in dataOption" :key="item.value" :label="item.label" :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="鏄惁鏄剧ず : " v-show="appendFrom.type == '2'"> + <el-radio v-model="appendFrom.isShow" label="0">鍚�</el-radio> + <el-radio v-model="appendFrom.isShow" label="1">鏄�</el-radio> + </el-form-item> + <el-form-item label="澶囨敞 : "> + <el-input v-model="appendFrom.bak"></el-input> + </el-form-item> + </el-form> + <span slot="footer" class="dialog-footer"> + <el-button @click="handleSubmitClose">鍙� 娑�</el-button> + <el-button type="primary" @click="handleSubmit">纭� 瀹�</el-button> + </span> + </el-dialog> + </div> +</template> + +<script> +import mapData from '@/assets/js/mapSdk/mapData.js'; +import { layer_selectAll, layer_insert, layer_delete, layer_updates, layer_update } from "@/api/mapView/map.js" +import configTools from '@/assets/js/configTools.js'; + +export default { + name: 'mapLayer', + components: {}, + data() { + return { + searchData: '', + placeholderData: '璇疯緭鍏ヨ鏌ヨ鐨勫浘灞傚悕绉�', + formInline: {}, + layerOption: [], + sourceOption: [], + dataOption: [], + treeData: [], + defaultProps: { + children: 'children', + label: 'cnName' + }, + activeNode: null, + activeNodeId: [], + formData: {}, + appendData: {}, + appendActive: false, + appendTitle: "", + appendFlag: null, + appendFrom: {}, + insertData: {}, + treeList: [], + }; + }, + created() { + this.setFormInlineStart(); + }, + watch: { + searchData(val) { + this.$refs.tree.filter(val); + }, + }, + mounted() { + this.setlayerStart(); + }, + methods: { + //鍥惧眰妯$硦鏌ヨ + filterNode(value, data) { + if (!value) return true; + return data.cnName.indexOf(value) !== -1; + }, + // 鏁版嵁鍒濆鍖� + setFormInlineStart() { + const layerData = mapData.layerData; + this.layerOption = layerData.layerOption; + this.sourceOption = layerData.sourceOption; + this.dataOption = layerData.dataOption; + this.formData = { + cnName: '', + type: this.layerOption[0].value, + serveType: this.sourceOption[0].value, + url: '', + dataType: this.dataOption[0].value, + isShow: '0', + bak: '' + } + this.formInline = { ... this.formData } + }, + // 鍥惧眰鏍戣幏鍙栨暟鎹� + setlayerStart() { + layer_selectAll().then(response => { + if (response.data && response.data.result && response.data.result.length > 0) { + const val = response.data.result; + this.treeList = val; + this.treeData = configTools.getTreeData(val) + this.$nextTick(() => { + + if (this.insertData && this.insertData.name) { + const obj = val.filter(item => { + if (item.pid == this.insertData.id && item.cnName == this.insertData.name) { + return item; + } + }) + if (obj && obj.length > 0) { + this.handleNodeClick(obj[0]) + + this.insertData = {} + } + } else if (!this.activeNode) { + if (this.treeData.length > 0) { + this.handleNodeClick(this.treeData[0]) + } + } else if (this.activeNode) { + this.handleNodeClick(this.activeNode) + } + }) + } + }) + }, + setLayerFormInline(res) { + res.type = res.type.toString(); + res.isShow = res.isShow.toString(); + res.isProject = res.isProject.toString(); + this.formInline = res + }, + //淇敼鎻愪氦 + onSubEdit() { + layer_update(this.formInline).then(response => { + if (response.data.code != 200) { + return this.$message({ + showClose: true, + message: '淇敼澶辫触', + type: 'error' + }); + } + this.$message({ + showClose: true, + message: '淇敼鎴愬姛', + type: 'success' + }); + this.setlayerStart(); + }) + }, + // 鍥惧眰鏍戠偣鍑� + handleNodeClick(res) { + const lid = res.id; + this.activeNodeId = [lid]; + this.$refs.tree.setCurrentKey(lid); + this.activeNode = this.$refs.tree.getNode(lid).data; + this.onCanelEdit(); + }, + // 閲嶇疆 + onCanelEdit() { + const val = { ... this.activeNode } + this.setLayerFormInline(val) + }, + //娣诲姞鑺傜偣 + setAddNode(res) { + this.appendTitle = res ? '鏂板鍚岀骇' : '鏂板瀛愮骇' + this.appendActive = true; + this.appendFrom = { ... this.formData } + }, + // 鍙栨秷娣诲姞 + handleSubmitClose() { + this.appendActive = false; + this.appendTitle = ""; + this.appendFrom = {}; + }, + setDelNode() { + layer_delete({ id: this.formInline.id }).then(response => { + if (response.data.code == 200) { + this.activeNode = null; + this.activeNodeId = null; + this.setlayerStart(); + this.$message({ + showClose: true, + message: '鍒犻櫎鎴愬姛', + type: 'success' + }); + } else { + this.$message({ + showClose: true, + message: '鍒犻櫎澶辫触', + type: 'error' + }); + } + }) + }, + getMaxOrderNum(res) { + var val = null; + for (var i in res) { + if (val) { + val = res[i].data.orderNum + } else { + if (res[i].data.orderNum > val) { + val = res[i].data.orderNum; + } + } + } + return val + 1; + }, + //娣诲姞鎻愪氦 + async handleSubmit() { + const isAddParent = this.appendTitle == "鏂板鍚岀骇" ? true : false; + const val = { ... this.appendFrom }; + val.isShow = parseInt(val.isShow); + val.isProject = parseInt(val.isProject); + val.level = isAddParent ? this.activeNode.level : this.activeNode.level + 1; + val.pid = isAddParent ? this.activeNode.pid : this.activeNode.id; + const pchildNodes = isAddParent ? this.$refs.tree.getNode(this.activeNode.id).parent.childNodes : this.$refs.tree.getNode(this.activeNode.id).childNodes + val.orderNum = this.getMaxOrderNum(pchildNodes); + if (this.treeData.length <= 0) { + val.pid = 0; + val.orderNum = 1; + val.lever = 1; + } + this.insertData = { + name: val.cnName, + id: val.pid + } + const response = await layer_insert(val); + if (response.data.code == 200) { + this.$message({ + showClose: true, + message: '娣诲姞鎴愬姛', + type: 'success' + }); + this.handleSubmitClose(); + this.setlayerStart(); + } else { + this.$message({ + showClose: true, + message: '娣诲姞澶辫触', + type: 'error' + }); + } + }, + // 鍚戜笂绉诲姩 + setMoveUp() { + let node = this.$refs.tree.getCurrentNode(); + let pchildNodes = this.$refs.tree.getNode(node.id).parent.childNodes; + let currentId = null; + for (let i = 0; i < pchildNodes.length; i++) { + if (pchildNodes[i].data.id == node.id) { + currentId = i; + } + } + if (currentId == 0) { + return this.$message({ + message: "澶勪簬椤剁锛屼笉鑳界户缁笂绉�", + type: "warning", + }); + } + const tempChildrenNodex1 = pchildNodes[currentId - 1]; + const tempChildrenNodex2 = pchildNodes[currentId]; + var arr = []; + this.treeList.filter((res) => { + if (res.id == tempChildrenNodex2.data.id) { + arr.push(res); + } else if (res.id == tempChildrenNodex1.data.id) { + arr.push(res); + } + }); + const orderNum = arr[1].orderNum + arr[1].orderNum = arr[0].orderNum + arr[0].orderNum = orderNum + this.sendChange(arr) + }, + // 鍚戜笅绉诲姩 + setMoveDown() { + let node = this.$refs.tree.getCurrentNode(); + let pchildNodes = this.$refs.tree.getNode(node.id).parent.childNodes; + let currentId = null; + for (let i = 0; i < pchildNodes.length; i++) { + if (pchildNodes[i].data.id == node.id) { + currentId = i; + } + } + if (currentId > pchildNodes.length - 1) { + return this.$message({ + message: "澶勪簬搴曠锛屼笉鑳界户缁笂绉�", + type: "warning", + }); + } + const tempChildrenNodex1 = pchildNodes[currentId + 1]; + const tempChildrenNodex2 = pchildNodes[currentId]; + var arr = []; + this.treeList.filter((res) => { + if (res.id == tempChildrenNodex2.data.id) { + arr.push(res); + } else if (res.id == tempChildrenNodex1.data.id) { + arr.push(res); + } + }); + const orderNum = arr[1].orderNum + arr[1].orderNum = arr[0].orderNum + arr[0].orderNum = orderNum; + this.sendChange(arr) + }, + sendChange(res) { + layer_updates(res).then(response => { + if (response.data.code != 200) { + return this.$message({ + showClose: true, + message: '绉诲姩澶辫触', + type: 'error' + }); + } + this.setlayerStart(); + }) + } + + }, +}; +</script> + +<style lang="scss" scoped> +.layerBox { + width: calc(100% - 20px); + height: calc(100% - 20px); + position: absolute; + margin: 10px; + border-radius: 5px; + display: flex; + + .leftTree { + width: 20%; + height: 100%; + margin-right: 10px; + + .treeCard { + height: 100%; + + + ::v-deep.el-card__body { + height: 100%; + display: flex; + flex-direction: column; + } + + .treeBox { + margin-top: 10px; + flex: 1; + overflow: auto; + } + } + + ::v-deep .el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content { + color: #409EFF; + } + } + + .rightContent { + flex: 1; + + .contentMenu { + display: flex; + justify-content: flex-end; + } + + ::v-deep .el-divider--horizontal { + margin: 15px 0px; + } + } +} +</style> + + +</style> diff --git a/src/views/visual/mapView/attributeInfo.vue b/src/views/visual/mapView/attributeInfo.vue new file mode 100644 index 0000000..89f9f95 --- /dev/null +++ b/src/views/visual/mapView/attributeInfo.vue @@ -0,0 +1,171 @@ +<template> + <Popup ref="pop" top="20px" :title="title" @close="close(true)" width="1000px" :maxHeight="'700px'" + @cancel="close(false)"> + <div class="menuBox"> + <div class="serachContent"> + <el-form :inline="true" :model="formInline" class="demo-form-inline"> + <el-form-item label="鍚嶇О"> + <el-input size="small" v-model="formInline.name" placeholder="璇疯緭鍏ュ畾浣嶅悕绉�..."></el-input> + </el-form-item> + <el-form-item> + <el-button size="small" plain type="primary" @click="setInfoSearch" + icon="el-icon-search">鏌ヨ</el-button> + </el-form-item> + <el-form-item> + <el-button size="small" plain type="info" @click="setInfoRefresh" + icon="el-icon-refresh">閲嶇疆</el-button> + </el-form-item> + </el-form> + </div> + <div class="tableContent"> + <div class="tableBox"> + <el-table :data="tableData" border height="calc(100% - 2px)" ref="filterTable" style="width: 100%"> + <el-table-column label="瀹氫綅" width="100" align="center"> + <template slot-scope="scope"> + <el-button icon="el-icon-map-location" size="small" + @click="spaceLocation(scope.$index, scope.row)"></el-button> + </template> + </el-table-column> + <el-table-column label="鍚嶇О" prop="name" align="center"></el-table-column> + <el-table-column label="鐜嚎" prop="line" align="center"></el-table-column> + <el-table-column label="绫诲瀷" prop="type" align="center"></el-table-column> + <el-table-column label="浣嶇疆" prop="geom" align="center"></el-table-column> + </el-table> + </div> + + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageIndex" + :limit.sync="queryParams.pageSize" @pagination="getAttributeInfo" /> + </div> + </div> + </Popup> +</template> + +<script> +import Popup from '@/components/Tool/Popup.vue'; +import { zhangzitou_selectAll } from "@/api/mapView/map.js" +import mapConfig from '../../../assets/js/mapSdk/mapConfig'; + + +export default { + name: 'attributeInfo', + components: { Popup }, + data() { + return { + title: '灞炴�т俊鎭�', + total: 0, + queryParams: { + pageIndex: 1, + pageSize: 10, + name: "", + srid: 4326, + }, + billboardEntity: null, + formInline: { + name: '' + } + }; + }, + methods: { + // 鍏抽棴寮圭獥 + close(isCloseBtn, removeLayer = true) { + // removeLayer && this.removeImageLayer(); + this.delBillboard(); + // 閲嶇疆data鍊� + Object.assign(this.$data, this.$options.data()); + !isCloseBtn && this.$refs.pop.close(); + }, + + // 鎵撳紑寮圭獥 + open() { + this.close(true); + this.$refs.pop.open(); + this.getAttributeInfo(); + }, + setInfoSearch() { + this.queryParams.name = this.formInline.name; + this.getAttributeInfo(); + }, + setInfoRefresh() { + this.formInline.name = ""; + this.queryParams.pageIndex = 1; + this.queryParams.pageSize = 10; + this.setInfoSearch(); + }, + getAttributeInfo() { + zhangzitou_selectAll({ + name: this.queryParams.name, + page: this.queryParams.pageIndex, + limit: this.queryParams.pageSize, + srid: this.queryParams.srid + }).then(response => { + if (response.data.code != 200) return; + const valDta = response.data.result; + this.total = valDta.total; + this.tableData = valDta.pois + }) + }, + delBillboard() { + if (this.billboardEntity) { + this.billboardEntity.removeFromMap(); + this.billboardEntity = null; + return + } + }, + spaceLocation(index, row) { + var wkt = mapConfig.getWKTParse(row.geom); + this.delBillboard(); + const url = config.sdkImg + 'Workers/image/mark.png'; + this.billboardEntity = earthCtrl.factory.createBillboard({ + name: "鏍囩鐐�", + image: url, + width: 16, + height: 22, + lon: wkt.coordinates[0], + lat: wkt.coordinates[1], + alt: 10, + scale: 1.5, + }); + earthCtrl.userScene.flyTo(this.billboardEntity) + + }, + + + + + + }, +}; +</script> + +<style lang="scss" scoped> +.menuBox { + position: relative; + height: 660px; + width: calc(100% - 0px); + padding: 10px; + display: flex; + flex-direction: column; + + .serachContent { + display: flex; + } + + .tableContent { + flex: 1; + display: flex; + flex-direction: column; + background: #ffffff; + + .tableBox { + flex: 1; + + } + + .pagination-container { + padding: 0px 10px !important; + } + + } + +} +</style> diff --git a/src/views/visual/mapView/dataAnalysis.vue b/src/views/visual/mapView/dataAnalysis.vue new file mode 100644 index 0000000..b86ef29 --- /dev/null +++ b/src/views/visual/mapView/dataAnalysis.vue @@ -0,0 +1,44 @@ +<template> + <Popup ref="pop" top="20px" :title="title" @close="close(true)" width="1400px" :maxHeight="'700px'" + @cancel="close(false)"> + <div class="menuBox"> + <analysis></analysis> + </div> + </Popup> +</template> + +<script> +import Popup from '@/components/Tool/Popup.vue'; +import analysis from '../analysis/index.vue' +export default { + name: 'dataAnalysis', + components: { Popup, analysis }, + data() { + return { + title: '鏁版嵁鍒嗘瀽', + }; + }, + methods: { + // 鍏抽棴寮圭獥 + close(isCloseBtn, removeLayer = true) { + // removeLayer && this.removeImageLayer(); + // 閲嶇疆data鍊� + Object.assign(this.$data, this.$options.data()); + !isCloseBtn && this.$refs.pop.close(); + }, + // 鎵撳紑寮圭獥 + open() { + this.close(true); + this.$refs.pop.open(); + }, + }, +}; +</script> + +<style lang="scss" scoped> +.menuBox { + position: relative; + height: 680px; + width: 100%; +} +</style> diff --git a/src/views/visual/mapView/dataStatistics.vue b/src/views/visual/mapView/dataStatistics.vue new file mode 100644 index 0000000..7d6735f --- /dev/null +++ b/src/views/visual/mapView/dataStatistics.vue @@ -0,0 +1,157 @@ +<template> + <Popup ref="pop" top="20px" :title="title" @close="close(true)" width="1000px" :maxHeight="'700px'" + @cancel="close(false)"> + <div class="menuBox"> + <div class="serachContent"> + <el-select v-model="linesName" @change="setEchartChange" placeholder="璇烽�夋嫨"> + <el-option v-for="(item, key) in linesOption" :key="key" :label="item.line" :value="item.line"> + </el-option> + </el-select> + </div> + <div class="echartContent"> + <div id="myEchart" class="myChart"> </div> + </div> + </div> + </Popup> +</template> + +<script> +import Popup from '@/components/Tool/Popup.vue'; +import { zhangzitou_selectInfos } from "@/api/mapView/map.js" +import mapData from '@/assets/js/mapSdk/mapData'; +import * as echarts from 'echarts'; +export default { + name: 'dataAnalysis', + components: { Popup }, + data() { + return { + title: '鏁版嵁缁熻', + allLines: [], + linesOption: [], + linesName: '', + myChart: null, + }; + }, + methods: { + // 鍏抽棴寮圭獥 + close(isCloseBtn, removeLayer = true) { + // removeLayer && this.removeImageLayer(); + // 閲嶇疆data鍊� + Object.assign(this.$data, this.$options.data()); + !isCloseBtn && this.$refs.pop.close(); + }, + // 鎵撳紑寮圭獥 + open() { + this.close(true); + this.$refs.pop.open(); + this.getAllLines(); + }, + getAllLines() { + zhangzitou_selectInfos().then(response => { + if (response.data.code != 200) { + return this.close(); + } + this.setAllLinses(response.data.result) + }) + }, + setAllLinses(res) { + this.allLines = res; + this.linesOption = this.allLines.filter((item, index, self) => + index === self.findIndex((t) => t.line === item.line) + ); + this.linesName = this.linesOption[0].line; + this.setEchartChange(); + }, + setEchartChange() { + zhangzitou_selectInfos({ + line: this.linesName + }).then(response => { + if (response.data.code != 200) return + const result = response.data.result; + + const objData = [] + result.filter(item => { + const type = mapData.dataStatistics[item.type]; + if (type) { + item.type = type + } + objData.push({ + value: item.count, name: item.type + }) + }) + this.setEchartShow(objData) + }) + + }, + + setEchartShow(res) { + + let option = { + title: { + + left: 'center' + }, + tooltip: { + trigger: 'item' + }, + legend: { + orient: 'vertical', + left: 'left' + }, + series: [ + { + name: this.linesName, + type: 'pie', + radius: '50%', + data: res, + emphasis: { + itemStyle: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + } + ] + }; + if (!this.myChart) { + + this.myChart = echarts.init(document.getElementById("myEchart")); + } + + + this.myChart.setOption(option); + window.addEventListener("resize", () => { + this.myChart.resize(); + }); + }, + }, +}; +</script> + +<style lang="scss" scoped> +.menuBox { + position: relative; + height: 660px; + width: calc(100% - 0px); + padding: 10px; + display: flex; + flex-direction: column; + + .serachContent { + display: flex; + } + + .echartContent { + flex: 1; + + + .myChart { + margin-top: 10px; + width: 100%; + height: calc(100% - 10px); + } + } + +} +</style> diff --git a/src/views/visual/mapView/index.vue b/src/views/visual/mapView/index.vue index a1378c1..539c4f3 100644 --- a/src/views/visual/mapView/index.vue +++ b/src/views/visual/mapView/index.vue @@ -13,7 +13,8 @@ </span> <div v-if="item.children"> <el-dropdown-menu v-show="item.children" slot="dropdown"> - <el-dropdown-item style="text-align: center" :command="res" v-for="(res, key) in item.children" :key="key">{{ res.name }}</el-dropdown-item> + <el-dropdown-item style="text-align: center" :command="res" + v-for="(res, key) in item.children" :key="key">{{ res.name }}</el-dropdown-item> </el-dropdown-menu> </div> </el-dropdown> @@ -28,10 +29,22 @@ <i :size="20" class="el-icon-d-arrow-left"></i> </div> </div> + <!-- 鍥惧眰绠$悊 --> <layer-manager ref="layerManager"></layer-manager> + <!-- 鍧愭爣瀹氫綅 --> <location ref="location"></location> + <!-- 鐭ヨ瘑鍥捐氨 --> <knowledge ref="knowledge"></knowledge> + <!-- 绾胯矾婕父 --> <lineRoaming ref="lineRoaming"></lineRoaming> + <!-- 鍦颁笅妯″紡 --> + <undergroundMode ref="undergroundMode"></undergroundMode> + <!-- 鏁版嵁鍒嗘瀽 --> + <dataAnalysis ref="dataAnalysis"></dataAnalysis> + <!-- 鏁版嵁缁熻 --> + <dataStatistics ref="dataStatistics"></dataStatistics> + <!-- 灞炴�т俊鎭� --> + <attributeInfo ref="attributeInfo"></attributeInfo> </div> </div> </template> @@ -44,10 +57,17 @@ import location from './location.vue'; import knowledge from './knowledge.vue'; import lineRoaming from './lineRoaming.vue'; - +import { layer_selectAll } from "@/api/mapView/map.js"; +import configTools from '@/assets/js/configTools'; +import store from "@/store"; +import mapServer from '@/assets/js/mapSdk/mapServe'; +import undergroundMode from './undergroundMode.vue'; +import dataAnalysis from './dataAnalysis.vue'; +import dataStatistics from './dataStatistics.vue' +import attributeInfo from './attributeInfo.vue'; export default { name: 'mapView', - components: { layerManager, location, knowledge, lineRoaming }, + components: { layerManager, location, knowledge, lineRoaming, undergroundMode, dataAnalysis, dataStatistics, attributeInfo }, data() { return { menuIsShow: false, @@ -58,13 +78,37 @@ }, mounted() { this.mapViewStart(); + + }, + beforeDestroy() { + this.$store.dispatch('mapLayers/changeLayerTree', []) + this.$store.dispatch('mapLayers/changeDefaultLayer', []) }, methods: { mapViewStart() { this.menuOption = mapData.menuData; this.$nextTick(() => { mapInit.Init(); + this.getSelectLayers(); }); + }, + getSelectLayers() { + layer_selectAll().then(response => { + if (response.data.code != 200) return + const defaultLayer = []; + const val = response.data.result.filter(item => { + item.checked = false; + if (item.type == 2 && item.isShow == 1) { + item.checked = true; + mapServer.addLayer(item) + defaultLayer.push(item.id) + } + return item; + }) + this.$store.dispatch('mapLayers/changeDefaultLayer', defaultLayer) + var obj = configTools.getTreeData(val) + this.$store.dispatch('mapLayers/changeLayerTree', obj) + }) }, setMenuClose() { this.menuIsShow = !this.menuIsShowx; @@ -86,6 +130,7 @@ this.$refs && this.$refs.knowledge && this.$refs.knowledge.close(); }, setPopShow(response) { + console.log(response); switch (response) { case '鍥惧眰绠$悊': this.$refs && this.$refs.layerManager && this.$refs.layerManager.open(); @@ -98,6 +143,18 @@ break; case '绾胯矾婕父': this.$refs && this.$refs.lineRoaming && this.$refs.lineRoaming.open(); + break; + case '鍦颁笅妯″紡': + this.$refs && this.$refs.undergroundMode && this.$refs.undergroundMode.open(); + break; + case '鏁版嵁鍒嗘瀽': + this.$refs && this.$refs.dataAnalysis && this.$refs.dataAnalysis.open(); + break; + case '灞炴�т俊鎭�': + this.$refs && this.$refs.attributeInfo && this.$refs.attributeInfo.open(); + break; + case '鏁版嵁缁熻': + this.$refs && this.$refs.dataStatistics && this.$refs.dataStatistics.open(); break; default: break; @@ -151,7 +208,7 @@ .closeMenu { width: 30px; height: 100%; - background: rgba(245, 245, 245, 1); + background: rgb(255, 255, 255); color: #4ab1fc; display: flex; position: relative; @@ -161,7 +218,7 @@ .menuItemBox { color: #7a7a7a; - background: rgba(245, 245, 245, 1); + background: rgb(255, 255, 255); line-height: 40px; padding: 0px 10px; font-size: 14px; diff --git a/src/views/visual/mapView/layerManager.vue b/src/views/visual/mapView/layerManager.vue index 2da6706..5ce9395 100644 --- a/src/views/visual/mapView/layerManager.vue +++ b/src/views/visual/mapView/layerManager.vue @@ -1,23 +1,42 @@ <template> - <Popup ref="pop" top="20px" left="calc(100% - 600px)" :title="title" @close="close(true)" width="300px" @cancel="close(false)"> - <el-tree></el-tree> + <Popup ref="pop" top="20px" left="calc(100% - 600px)" :title="title" @close="close(true)" width="300px" + @cancel="close(false)"> + + <div class="layerBox"> + <el-tree show-checkbox :data="treeData" ref="tree" node-key="id" :default-checked-keys="defaultLayer" + @check-change="handleCheckChange" :props="defaultProps"></el-tree> + </div> </Popup> </template> <script> import Popup from '@/components/Tool/Popup.vue'; +import store from "@/store"; +import mapServer from '@/assets/js/mapSdk/mapServe'; + export default { name: 'layerManager', components: { Popup }, + computed: { + getlayerTree() { + return store.getters.getlayerTree + } + }, data() { return { title: '鍥惧眰绠$悊', + defaultProps: { + children: 'children', + label: 'cnName' + }, + treeData: [], + defaultLayer: [], + ids: [], }; }, methods: { // 鍏抽棴寮圭獥 close(isCloseBtn, removeLayer = true) { - // removeLayer && this.removeImageLayer(); // 閲嶇疆data鍊� Object.assign(this.$data, this.$options.data()); !isCloseBtn && this.$refs.pop.close(); @@ -26,9 +45,87 @@ open() { this.close(true); this.$refs.pop.open(); + this.$nextTick(() => { + this.setLayerStart(); + }) + }, + setLayerStart() { + if (store.getters && store.getters.layerTree) { + this.defaultLayer = store.getters.defaultLayer; + this.ids = this.defaultLayer; + this.treeData = store.getters.layerTree + } + + }, + handleCheckChange(data, checked, indeterminate) { + const checkIds = this.$refs.tree.getCheckedKeys() + if (this.ids === checkIds) return + this.ids.map(o => { + if (checkIds.indexOf(o) < 0) { + const obj = this.$refs.tree.getNode(o); + console.log(obj.checked); + if (obj.checked) { + mapServer.addLayer(obj.data) + } else { + mapServer.removeLayer(obj.data) + } + } + }) + + checkIds.map(n => { + if (this.ids.indexOf(n) < 0) { + const obj = this.$refs.tree.getNode(n); + if (obj.checked) { + mapServer.addLayer(obj.data) + } else { + mapServer.removeLayer(obj.data) + } + } + }) + + + + this.$store.dispatch('mapLayers/changeLayerTree', this.treeData) + const ids = this.$refs.tree.getCheckedKeys() + this.ids = ids; + this.$store.dispatch('mapLayers/changeDefaultLayer', ids) + }, + setServerLayerChange(data, checked) { + if (checked) { + mapServer.addLayer(data) + } else { + mapServer.removeLayer(data) + } + + }, + getNodeList(list, checked) { + list.map(item => { + if (item.type == 1) { + if (item.children && item.children.length > 0) { + this.getNodeList(item.children) + } + } else { + this.setServerLayerChange(item, checked) + } + }) }, }, + + }; </script> -<style></style> +<style lang="scss" scoped> +.layerBox { + height: 680px; + + ::v-deep.el-tree { + background: transparent !important; + + .el-tree-node__content:hover { + color: #409EFF; + } + } + +} +</style> diff --git a/src/views/visual/mapView/lineRoaming.vue b/src/views/visual/mapView/lineRoaming.vue index 8ba57cd..5fb625a 100644 --- a/src/views/visual/mapView/lineRoaming.vue +++ b/src/views/visual/mapView/lineRoaming.vue @@ -1,19 +1,26 @@ <template> - <Popup ref="pop" top="20px" left="calc(100% - 600px)" :title="title" @close="close(true)" width="300px" :maxHeight="'700px'" @cancel="close(false)"> - <div class="menuBox"> - <el-form ref="form" label-width="80px"> - <el-form-item label="绾胯矾:"> - - </el-form-item> - <el-form-item label="绾胯矾:"> - - </el-form-item> - <el-form-item> - <el-button size="mini" >寮�濮嬫极娓�</el-button> - <el-button size="mini" >缁撴潫婕父</el-button> - </el-form-item> + <Popup ref="pop" top="20px" left="calc(100% - 600px)" :title="title" @close="close(true)" width="300px" + :maxHeight="'700px'" @cancel="close(false)"> + <div class="menuBox"> + <el-form ref="form" label-width="80px"> + <el-form-item label="绾胯矾:"> + <el-select v-model="value" @chagne="setLineOptionChagne" placeholder="璇烽�夋嫨"> + <el-option v-for="item in lineOption" :key="item.value" :label="item.name" :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="绾胯矾:"> + <el-select v-model="value1" placeholder="璇烽�夋嫨"> + <el-option v-for="item in lineOption1" :key="item.value" :label="item.name" :value="item.value"> + </el-option> + </el-select> + </el-form-item> + <el-form-item> + <el-button size="mini" @click="setRoamStart">寮�濮嬫极娓�</el-button> + <el-button size="mini" @click="setRoamStop">缁撴潫婕父</el-button> + </el-form-item> </el-form> - </div> + </div> </Popup> </template> @@ -22,20 +29,26 @@ import { zhangzitou_selectAllLine } from '@/api/mapView/map.js' +import WKT from 'terraformer-wkt-parser'; export default { name: 'location', components: { Popup }, data() { return { title: '绾胯矾婕父', + lineOption: [], + lineOption1: [], + lineObj: null, + value: '', + value1: '', + roamLine: null, }; }, - - + + methods: { // 鍏抽棴寮圭獥 close(isCloseBtn, removeLayer = true) { - // removeLayer && this.removeImageLayer(); // 閲嶇疆data鍊� Object.assign(this.$data, this.$options.data()); !isCloseBtn && this.$refs.pop.close(); @@ -46,14 +59,77 @@ this.$refs.pop.open(); this.romaLineStart(); }, - romaLineStart(){ - zhangzitou_selectAllLine({ + romaLineStart() { + zhangzitou_selectAllLine({ limit: 100000, page: 1 - }).then((response)=>{ - console.log(response); + }).then((response) => { + if (response.data.code != 200) return + this.lineOption = []; + this.lineObj = response.data.result.pois; + this.lineObj.map(item => { + if (this.lineOption.length == 0) { + this.lineOption.push({ + name: item.line, + value: item.line + }) + } else { + const n = this.lineOption.filter(r => { + if (r.name == item.line) { + return r + } + + }) + if (n.length == 0) { + this.lineOption.push({ + name: item.line, + value: item.line + }) + } + } + }) + this.value = this.lineOption[0].value + this.setLineOptionChagne(); }) }, + setLineOptionChagne() { + const a = this.value + this.lineOption1 = []; + this.lineObj.map(item => { + if (item.line == a) { + this.lineOption1.push({ + name: item.name, + value: item.geom, + }) + } + }) + this.value1 = this.lineOption1[0].value; + this.setLineOption1Chagne(); + + }, + setLineOption1Chagne() { + this.roamLine = this.value1; + }, + setRoamStart() { + if (!this.roamLine) return; + const obj = WKT.parse(this.roamLine).coordinates[0] + var degreesArr = obj.reduce((combined, current) => combined.concat(current), []); + earthCtrl.factory.getFlyData(degreesArr, data => { + data.showPoint = false; + data.showLine = true; + data.mode = 1; + + }) + }, + setRoamStop(){ + + }, + + + + + + }, }; </script> diff --git a/src/views/visual/mapView/location.vue b/src/views/visual/mapView/location.vue index 85f2da4..a6aa5b5 100644 --- a/src/views/visual/mapView/location.vue +++ b/src/views/visual/mapView/location.vue @@ -84,9 +84,7 @@ this.$refs[formName].validate((valid) => { if (valid) { this.setRemoveBillboard(); - const url = config.sdkImg + 'Workers/image/mark.png'; - console.log(url); this.billboard = Viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(this.modelFrom.lon, this.modelFrom.lat), // 璁剧疆瀹炰綋鍦ㄥ湴鐞冧笂鐨勪綅缃� billboard: { diff --git a/src/views/visual/mapView/undergroundMode.vue b/src/views/visual/mapView/undergroundMode.vue new file mode 100644 index 0000000..12dbcb6 --- /dev/null +++ b/src/views/visual/mapView/undergroundMode.vue @@ -0,0 +1,116 @@ +<template> + <Popup ref="pop" top="20px" left="calc(100% - 600px)" :maxHeight="'700px'" :title="title" @close="close(true)" + width="300px" @cancel="close(false)"> + <div style="padding: 10px;"> + <div class="underGroundBox"> + <el-switch class="elSwitch" @change="setUnderGroundCheck" v-model="value1" active-text="鍦颁笅妯″紡"> + </el-switch> + + <!-- <div class="contentRight"> + <el-switch class="elSwitch" v-model="value2" active-text="鍦颁笅缃戞牸"> + </el-switch> + </div> --> + </div> + <div class="underGroundBox"> + <span> + 閫忔槑搴� : + </span> + <div class="contentRight"> + <el-slider v-model="value3" @change="setAlphaChange" :format-tooltip="formatTooltip"></el-slider> + </div> + + </div> + </div> + + + </Popup> +</template> + +<script> +import Popup from '@/components/Tool/Popup.vue'; +export default { + name: 'location', + components: { Popup }, + data() { + return { + title: '鍦颁笅妯″紡', + value1: true, + value2: false, + value3: 50, + + }; + }, + methods: { + // 鍏抽棴寮圭獥 + close(isCloseBtn, removeLayer = true) { + // removeLayer && this.removeImageLayer(); + // 閲嶇疆data鍊� + this.value1 = false; + this.value3 = 50; + this.setUnderGroundCheck(); + this.setAlphaChange() + Object.assign(this.$data, this.$options.data()); + !isCloseBtn && this.$refs.pop.close(); + + }, + setUnderGroundCheck() { + earthCtrl.camera.undergroundMode = this.value1 + earthCtrl.camera.imageryLayerAlpha = this.value3 / 100 + }, + // 鎵撳紑寮圭獥 + open() { + this.close(true); + this.$refs.pop.open(); + + this.setUnderGroundCheck(); + }, + formatTooltip(val) { + return val + '%' + }, + setAlphaChange() { + earthCtrl.camera.imageryLayerAlpha = this.value3 / 100 + } + + + }, +}; +</script> + +<style lang="scss" scoped> +.elSwitch { + ::v-deep.el-switch__core { + border-radius: 10px !important; + width: 40px !important; + height: 20px; + } + + ::v-deep.el-switch__core:after { + width: 16px; + height: 16px; + border-radius: 100%; + + } + + +} + +.underGroundBox { + display: flex; + margin-bottom: 10px; + align-items: center; + + span { + font-size: 14px; + } + + .contentRight { + flex: 1; + margin-left: 10px; + } +} + +::v-deep .el-switch.is-checked .el-switch__core:after { + margin-left: -17px; + +} +</style> -- Gitblit v1.9.3