index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. <template>
  2. <div
  3. class="bs-design-wrap bs-bar"
  4. style="width: 100%; height: 100%"
  5. >
  6. <el-button v-if="currentDeep > 0" class="button" type='text' @click="jumpTo(config)"> 返回上一级</el-button>
  7. <div
  8. :id="`chart${config.code}`"
  9. style="width: 100%; height: 100%"
  10. />
  11. </div>
  12. </template>
  13. <script>
  14. import 'insert-css'
  15. import * as echarts from 'echarts'
  16. import {nameMap} from './json/mapData.js'
  17. import commonMixins from 'data-room-ui/js/mixins/commonMixins.js'
  18. import paramsMixins from 'data-room-ui/js/mixins/paramsMixins'
  19. import linkageMixins from 'data-room-ui/js/mixins/linkageMixins'
  20. export default {
  21. name: 'MapCharts',
  22. mixins: [paramsMixins, commonMixins, linkageMixins],
  23. props: {
  24. id: {
  25. type: String,
  26. default: ''
  27. },
  28. config: {
  29. type: Object,
  30. default: () => ({})
  31. }
  32. },
  33. data() {
  34. return {
  35. charts: null,
  36. hasData: false,
  37. level: '',
  38. option: {},
  39. mapList: [],
  40. currentDeep: 0,
  41. }
  42. },
  43. computed: {
  44. Data() {
  45. return JSON.parse(JSON.stringify(this.config))
  46. }
  47. },
  48. watch: {
  49. Data: {
  50. handler(newVal, oldVal) {
  51. if (newVal.w !== oldVal.w || newVal.h !== oldVal.h) {
  52. this.$nextTick(() => {
  53. this.charts.resize()
  54. })
  55. }
  56. },
  57. deep: true
  58. }
  59. },
  60. mounted() {
  61. this.chartInit()
  62. },
  63. beforeDestroy() {
  64. this.charts?.clear()
  65. },
  66. methods: {
  67. chartInit() {
  68. const config = this.config
  69. // key和code相等,说明是一进来刷新,调用list接口
  70. if (this.config.code === this.config.key || this.isPreview) {
  71. // 改变数据
  72. this.changeDataByCode(config).then((res) => {
  73. // 改变样式
  74. // config = this.changeStyle(res)
  75. this.newChart(config)
  76. }).catch(() => {
  77. })
  78. } else {
  79. // 否则说明是更新,这里的更新只指更新数据(改变样式时是直接调取changeStyle方法),因为更新数据会改变key,调用chart接口
  80. this.changeData(config).then((res) => {
  81. // 初始化图表
  82. this.newChart(res)
  83. })
  84. }
  85. },
  86. dataFormatting(config, data) {
  87. config.option = {
  88. ...config.option,
  89. data: data?.data
  90. }
  91. return config
  92. },
  93. async jumpTo(config) {
  94. this.currentDeep--
  95. let map = this.mapList[this.currentDeep]
  96. // 移除mapList中的最后一个元素
  97. this.mapList.pop()
  98. let mapData = JSON.parse(map.geoJson)
  99. this.option.geo.map = map.name;
  100. this.changeData({...config, customize: {...config.customize, level: map.level, scope: map.name}})
  101. echarts.registerMap(map.name, mapData);
  102. this.charts.setOption(this.option, true);
  103. },
  104. async newChart(config) {
  105. this.charts = echarts.init(
  106. document.getElementById(`chart${this.config.code}`)
  107. )
  108. this.level = config.customize.level
  109. const lines_coord = []
  110. let fromCoord = []
  111. let coord = []
  112. let hasMapId = !!config.customize.mapId
  113. // 根据mapId获取地图数据
  114. let mapInfoUrl = `${window.BS_CONFIG?.httpConfigs?.baseURL}/bigScreen/map/info/${config.customize.mapId}`
  115. // 如果设置了地图id,就用地图id获取地图数据,否则用默认的世界地图
  116. if (!hasMapId) {
  117. mapInfoUrl = `${window.BS_CONFIG?.httpConfigs?.baseURL}/bigScreen/map/default/worldMap/world`
  118. }
  119. this.$dataRoomAxios.get(mapInfoUrl, {}, true).then(res => {
  120. if (this.config.option.data) {
  121. // 起点名称
  122. const fromName = config.customize.dataField?.fromName || 'from'
  123. // 起点经度
  124. const fromLng = config.customize.dataField?.fromLng || 'lng1'
  125. // 起点纬度
  126. const fromLat = config.customize.dataField?.fromLat || 'lat1'
  127. // 终点名称
  128. const toName = config.customize.dataField?.toName || 'to'
  129. // 终点经度
  130. const toLng = config.customize.dataField?.toLng || 'lng2'
  131. // 终点纬度
  132. const toLat = config.customize.dataField?.toLat || 'lat2'
  133. // 值
  134. const value = config.customize.dataField?.value || 'value'
  135. this.config.option.data.forEach(val => {
  136. // 飞线
  137. lines_coord.push({value: val[value], msg: {...val}, coords: [[val[fromLat], val[fromLng]], [val[toLat], val[toLng]]]})
  138. // 起点散点
  139. fromCoord.push({name: val[fromName], value: [val[fromLat], val[fromLng], val[value]], msg: {...val}})
  140. // 终点散点
  141. coord.push({name: val[toName], value: [val[toLat], val[toLng], val[value]], msg: {...val}})
  142. })
  143. }
  144. let mapData = hasMapId ? JSON.parse(res.data.geoJson) : res
  145. if (hasMapId && res.data.uploadedGeoJson !== 1) {
  146. // 没有上传过geoJson
  147. this.$message({
  148. message: '请先上传地图数据',
  149. type: 'warning'
  150. })
  151. return
  152. }
  153. this.mapList.push(res.data)
  154. echarts.registerMap(config.customize.scope, mapData)
  155. this.option = {
  156. nameMap: config.customize.level == '0' ? nameMap : '',
  157. // graphic: [
  158. // ],
  159. geo: {
  160. map: config.customize.scope,
  161. zlevel: 10,
  162. show: true,
  163. layoutCenter: ['50%', '50%'],
  164. roam: true,
  165. layoutSize: "100%",
  166. zoom: 1,
  167. label: {
  168. // 通常状态下的样式
  169. normal: {
  170. show: config.customize.mapName,
  171. textStyle: {
  172. color: config.customize.mapNameColor || '#fff',
  173. fontSize: config.customize.mapNameSize || 12,
  174. fontWeight: config.customize.mapNameWeight || 500
  175. }
  176. },
  177. // 鼠标放上去的样式
  178. emphasis: {
  179. textStyle: {
  180. color: config.customize.mapNameColor || '#fff',
  181. fontSize: config.customize.mapNameSize || 12,
  182. fontWeight: config.customize.mapNameWeight || 500
  183. }
  184. }
  185. },
  186. // 地图区域的样式设置
  187. itemStyle: {
  188. normal: {
  189. borderColor: config.customize.mapLineColor,
  190. borderWidth: 1,
  191. areaColor: config.customize.areaColor,
  192. shadowColor: 'fffff',
  193. shadowOffsetX: -2,
  194. shadowOffsetY: 2,
  195. shadowBlur: 10
  196. },
  197. // 鼠标放上去高亮的样式
  198. emphasis: {
  199. areaColor: '#389BB7',
  200. borderWidth: 0
  201. }
  202. }
  203. },
  204. tooltip: {
  205. backgroundColor: config.customize.tooltipBackgroundColor,
  206. borderColor: config.customize.borderColor,
  207. show: true,
  208. textStyle: {
  209. color: config.customize.fontColor,
  210. },
  211. },
  212. series: [
  213. {
  214. type: 'effectScatter',
  215. coordinateSystem: 'geo',
  216. zlevel: 15,
  217. symbolSize: 8,
  218. rippleEffect: {
  219. period: 4, brushType: 'stroke', scale: 4
  220. },
  221. tooltip: {
  222. trigger: 'item',
  223. formatter(params) {
  224. const a = eval(config.customize.scatterFormatter)
  225. return a
  226. },
  227. },
  228. itemStyle: {
  229. color: config.customize.scatterColor,
  230. opacity: 1
  231. },
  232. data: coord
  233. },
  234. {
  235. type: 'effectScatter',
  236. coordinateSystem: 'geo',
  237. zlevel: 15,
  238. symbolSize: 12,
  239. tooltip: {
  240. trigger: 'item',
  241. formatter(params) {
  242. const a = eval(config.customize.scatterFormatter)
  243. return a
  244. },
  245. },
  246. rippleEffect: {
  247. period: 6, brushType: 'stroke', scale: 8
  248. },
  249. itemStyle: {
  250. color: config.customize.scatterCenterColor,
  251. opacity: 1
  252. },
  253. data: fromCoord
  254. },
  255. {
  256. type: 'lines',
  257. coordinateSystem: 'geo',
  258. zlevel: 15,
  259. tooltip: {
  260. trigger: 'item',
  261. formatter(params) {
  262. const a = eval(config.customize.lineFormatter)
  263. return a
  264. },
  265. },
  266. effect: {
  267. show: true,
  268. period: 5,
  269. trailLength: 0,
  270. symbol: config.customize.symbol,
  271. color: config.customize.symbolColor,
  272. symbolSize: config.customize.symbolSize,
  273. },
  274. lineStyle: {
  275. normal: {
  276. color: function (value) {
  277. return '#ffffff'
  278. }, width: 2, opacity: 0.6, curveness: 0.2
  279. }
  280. },
  281. data: lines_coord
  282. }
  283. ]
  284. }
  285. if (config.customize.visual) {
  286. this.option.visualMap = {
  287. show: false,
  288. min: config.customize.range[0],
  289. max: config.customize.range[1],
  290. seriesIndex: [0, 2],
  291. inRange: {
  292. color: config.customize.rangeColor
  293. }
  294. }
  295. }
  296. this.charts.setOption(this.option)
  297. // 点击下钻
  298. this.charts.on('click', async (params) => {
  299. if (params.name == '') return
  300. if (!config.customize.down) {
  301. return
  302. }
  303. // 到达允许下钻的层数,则不再下钻
  304. if (this.currentDeep >= config.customize.downLevel) return
  305. const mapUrl = `${window.BS_CONFIG?.httpConfigs?.baseURL}/bigScreen/map/data/${this.mapList[this.currentDeep].id}/${params.name}`
  306. const map = await this.$dataRoomAxios.get(decodeURI(mapUrl), {}, false)
  307. // 地图不可用
  308. if (map.available !== 1) {
  309. this.$message({
  310. message: '未找到该地图配置',
  311. type: 'warning'
  312. })
  313. return
  314. }
  315. this.currentDeep++
  316. this.mapList.push(map)
  317. this.changeData({...config, customize: {...config.customize, scope: params.name}})
  318. this.option.geo.map = params.name
  319. echarts.registerMap(params.name, JSON.parse(map.geoJson));
  320. this.charts.setOption(this.option, true);
  321. });
  322. })
  323. }
  324. }
  325. }
  326. </script>
  327. <style lang="scss" scoped>
  328. @import '../../assets/style/echartStyle';
  329. .light-theme {
  330. background-color: #ffffff;
  331. color: #000000;
  332. }
  333. .auto-theme {
  334. background-color: rgba(0, 0, 0, 0);
  335. }
  336. .bs-design-wrap {
  337. position: relative;
  338. .button {
  339. position: absolute;
  340. z-index: 999;
  341. }
  342. }
  343. </style>