Commit 38f8e17d8940c4497aaa16eb68a712d81ebd45fc

Authored by fengwotao
1 parent 3b34bcf0

feat(src/packages): 图表地图支持下钻 修改地图注册方式为服务端接口请求

@@ -13,7 +13,8 @@ enum Api { @@ -13,7 +13,8 @@ enum Api {
13 VIDEO = '/video/list', 13 VIDEO = '/video/list',
14 DEVICE_PROFILE = '/device_profile/me/list', 14 DEVICE_PROFILE = '/device_profile/me/list',
15 DEVICE = '/device', 15 DEVICE = '/device',
16 - VIDEOURL = '/video/url/' 16 + VIDEOURL = '/video/url/',
  17 + GEOJSONURL = '/map/geo_json/'
17 } 18 }
18 19
19 export const getDictItemByCode = (value: string) => { 20 export const getDictItemByCode = (value: string) => {
@@ -106,3 +107,9 @@ export const getVideoUrl = (id: string) => @@ -106,3 +107,9 @@ export const getVideoUrl = (id: string) =>
106 defHttp.get({ 107 defHttp.get({
107 url: `${Api.VIDEOURL}${id}` 108 url: `${Api.VIDEOURL}${id}`
108 }) 109 })
  110 +
  111 +//获取行政区域
  112 +export const getGeoJsonMap = (code: number, level: string) =>
  113 + defHttp.get({
  114 + url: `${Api.GEOJSONURL}${code}/${level}`
  115 + })
@@ -24,7 +24,8 @@ const selectOptions = reactive({ @@ -24,7 +24,8 @@ const selectOptions = reactive({
24 const selectValues = reactive({ 24 const selectValues = reactive({
25 provinceValue: 'china', 25 provinceValue: 'china',
26 cityValue: null, 26 cityValue: null,
27 - countyValue: null 27 + countyValue: null,
  28 + levelStr: areaEnum.COUNTRY
28 }) 29 })
29 30
30 const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => { 31 const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
@@ -49,13 +50,15 @@ onMounted(async () => { @@ -49,13 +50,15 @@ onMounted(async () => {
49 const onHandleSelectProvince = async (value: number | string) => { 50 const onHandleSelectProvince = async (value: number | string) => {
50 selectValues.cityValue = null 51 selectValues.cityValue = null
51 selectValues.countyValue = null 52 selectValues.countyValue = null
52 - if (value === 'china') return 53 + if (value === 'china') return (selectValues.levelStr = areaEnum.COUNTRY)
53 selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value as any) 54 selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value as any)
  55 + selectValues.levelStr = areaEnum.PROVINCE
54 } 56 }
55 57
56 const onHandleSelectCity = async (value: number) => { 58 const onHandleSelectCity = async (value: number) => {
57 selectValues.countyValue = null 59 selectValues.countyValue = null
58 selectOptions.countryOptions = await getAreaLists(areaEnum.COUNTY, value) 60 selectOptions.countryOptions = await getAreaLists(areaEnum.COUNTY, value)
  61 + selectValues.levelStr = areaEnum.CITY
59 } 62 }
60 63
61 const onHandleSubmit = () => { 64 const onHandleSubmit = () => {
@@ -7,23 +7,27 @@ import dataJson from './data.json' @@ -7,23 +7,27 @@ import dataJson from './data.json'
7 7
8 //省市区枚举 8 //省市区枚举
9 export const enum areaEnum { 9 export const enum areaEnum {
10 - PROVINCE = 'PROVINCE',  
11 - CITY = 'CITY',  
12 - COUNTY = 'COUNTY' 10 + PROVINCE = 'PROVINCE',//省份
  11 + CITY = 'CITY',//城市
  12 + COUNTY = 'COUNTY',//县
  13 + COUNTRY = 'COUNTRY',//国家
  14 + TOWN = 'TOWN'//镇
13 } 15 }
14 export const includes = [] 16 export const includes = []
15 17
16 export const option = { 18 export const option = {
17 - iconColor:'black',  
18 - showIcon:false,  
19 - iconDistanceRight:20,  
20 - iconDistanceTop:20, 19 + iconColor: 'black',
  20 + showIcon: false,
  21 + iconDistanceRight: 20,
  22 + iconDistanceTop: 20,
21 drillingIn: false, 23 drillingIn: false,
22 dataset: dataJson, 24 dataset: dataJson,
23 mapRegion: { 25 mapRegion: {
24 adcode: 'china', 26 adcode: 'china',
25 showHainanIsLands: true, 27 showHainanIsLands: true,
26 - saveSelect:{} 28 + saveSelect: {
  29 + levelStr: areaEnum.COUNTRY
  30 + }
27 }, 31 },
28 tooltip: { 32 tooltip: {
29 show: true, 33 show: true,
@@ -157,7 +161,7 @@ export const option = { @@ -157,7 +161,7 @@ export const option = {
157 shadowOffsetY: 2, 161 shadowOffsetY: 2,
158 shadowBlur: 10 162 shadowBlur: 10
159 } 163 }
160 - }, 164 + }
161 ] 165 ]
162 } 166 }
163 export const MapDefaultConfig = { ...option } 167 export const MapDefaultConfig = { ...option }
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 :theme="themeColor" 6 :theme="themeColor"
7 :option="option.value" 7 :option="option.value"
8 :manual-update="isPreview()" 8 :manual-update="isPreview()"
  9 + :loading="loading"
9 autoresize 10 autoresize
10 > 11 >
11 </v-chart> 12 </v-chart>
@@ -13,7 +14,7 @@ @@ -13,7 +14,7 @@
13 14
14 <script setup lang="ts"> 15 <script setup lang="ts">
15 import { PropType, reactive, watch, ref, nextTick } from 'vue' 16 import { PropType, reactive, watch, ref, nextTick } from 'vue'
16 -import config, { includes } from './config' 17 +import config, { includes, areaEnum } from './config'
17 import VChart from 'vue-echarts' 18 import VChart from 'vue-echarts'
18 import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook' 19 import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
19 import { use, registerMap } from 'echarts/core' 20 import { use, registerMap } from 'echarts/core'
@@ -25,9 +26,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore @@ -25,9 +26,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
25 import { isPreview } from '@/utils' 26 import { isPreview } from '@/utils'
26 import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json' 27 import mapJsonWithoutHainanIsLands from './mapWithoutHainanIsLands.json'
27 import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components' 28 import { DatasetComponent, GridComponent, TooltipComponent, GeoComponent, VisualMapComponent } from 'echarts/components'
28 -import cityMap from './mapGeojson/china-main-city-map.json'  
29 -  
30 -type historyDataType = { name: string; code: string } 29 +import { getGeoJsonMap } from '@/api/external/common'
31 30
32 const props = defineProps({ 31 const props = defineProps({
33 themeSetting: { 32 themeSetting: {
@@ -57,14 +56,12 @@ use([ @@ -57,14 +56,12 @@ use([
57 VisualMapComponent 56 VisualMapComponent
58 ]) 57 ])
59 58
60 -const saveSelectValue = ref('') 59 +const loading = ref(true)
61 60
62 const iconStr = ref( 61 const iconStr = ref(
63 'path://M853.333333 245.333333H245.333333l93.866667-93.866666c12.8-12.8 12.8-34.133333 0-46.933334-12.8-12.8-34.133333-12.8-46.933333 0l-145.066667 145.066667c-12.8 12.8-12.8 34.133333 0 46.933333l145.066667 145.066667c6.4 6.4 14.933333 10.666667 23.466666 10.666667s17.066667-4.266667 23.466667-10.666667c12.8-12.8 12.8-34.133333 0-46.933333L256 311.466667h597.333333c6.4 0 10.666667 4.266667 10.666667 10.666666v426.666667c0 6.4-4.266667 10.666667-10.666667 10.666667H170.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h682.666666c40.533333 0 74.666667-34.133333 74.666667-74.666667V320c0-40.533333-34.133333-74.666667-74.666667-74.666667z' 62 'path://M853.333333 245.333333H245.333333l93.866667-93.866666c12.8-12.8 12.8-34.133333 0-46.933334-12.8-12.8-34.133333-12.8-46.933333 0l-145.066667 145.066667c-12.8 12.8-12.8 34.133333 0 46.933333l145.066667 145.066667c6.4 6.4 14.933333 10.666667 23.466666 10.666667s17.066667-4.266667 23.466667-10.666667c12.8-12.8 12.8-34.133333 0-46.933333L256 311.466667h597.333333c6.4 0 10.666667 4.266667 10.666667 10.666666v426.666667c0 6.4-4.266667 10.666667-10.666667 10.666667H170.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h682.666666c40.533333 0 74.666667-34.133333 74.666667-74.666667V320c0-40.533333-34.133333-74.666667-74.666667-74.666667z'
64 ) 63 )
65 64
66 -const historyData = ref<historyDataType[]>([])  
67 -  
68 const option = reactive({ 65 const option = reactive({
69 value: mergeTheme(props.chartConfig.option, props.themeSetting, includes) 66 value: mergeTheme(props.chartConfig.option, props.themeSetting, includes)
70 }) 67 })
@@ -105,28 +102,52 @@ props.chartConfig.option = { @@ -105,28 +102,52 @@ props.chartConfig.option = {
105 ...{ toolbox: toolBoxOption.value } 102 ...{ toolbox: toolBoxOption.value }
106 } 103 }
107 104
108 -//地图点击返回  
109 -const watchAdcode = () => { 105 +//地图点击返回 adcode=100000,名字必须是china
  106 +const watchAdcode = async () => {
110 if (props.chartConfig.option.drillingIn) { 107 if (props.chartConfig.option.drillingIn) {
111 - const code = historyData.value.at(-2)?.code  
112 - props.chartConfig.option.mapRegion.adcode = code ? code : 'china'  
113 - historyData.value.pop() 108 + saveLevelStr.level = saveLevelStr.parentInfo.level
  109 + await getGeojson(saveLevelStr.parentInfo.adcode)
  110 + props.chartConfig.option.geo.map =
  111 + saveLevelStr.parentInfo.adcode === 100000 ? 'china' : saveLevelStr.parentInfo.adcode
  112 + props.chartConfig.option.series.forEach((item: any) => {
  113 + if (item.type === 'map')
  114 + item.map = saveLevelStr.parentInfo.adcode === 100000 ? 'china' : saveLevelStr.parentInfo.adcode
  115 + })
  116 + vEchartsSetOption()
114 } 117 }
115 } 118 }
116 119
117 const vChartRef = ref<typeof VChart>() 120 const vChartRef = ref<typeof VChart>()
118 121
119 -//动态获取json注册地图  
120 -const getGeojson = (regionId: string) => { 122 +const saveGeojson: any = ref({}) // 保存geojson
  123 +
  124 +const chinaDefaultRegionId = ref(100000) //如果是china则adcode为100000
  125 +
  126 +const saveLevelStr = reactive({
  127 + // 保存行政级别和上一级的adcode和level
  128 + level: '',
  129 + parentInfo: {
  130 + adcode: 0,
  131 + level: ''
  132 + }
  133 +})
  134 +
  135 +//动态注册地图
  136 +const getGeojson = async (regionId: any) => {
121 try { 137 try {
122 - return new Promise<boolean>(resolve => {  
123 - import(`./mapGeojson/${regionId}.json`).then(data => {  
124 - registerMap(regionId, { geoJSON: data.default as any, specialAreas: {} })  
125 - resolve(true)  
126 - })  
127 - })  
128 - } finally {  
129 - console.log 138 + const { levelStr } = props.chartConfig.option.mapRegion.saveSelect //右侧配置项获取的行政级别
  139 + const { data } = await getGeoJsonMap(
  140 + regionId === 'china' ? chinaDefaultRegionId.value : regionId,
  141 + !saveLevelStr.level ? levelStr : saveLevelStr.level
  142 + )
  143 + const { geoJson, name, code, level } = data
  144 + const geoJsonFile = JSON.parse(geoJson)
  145 + saveGeojson.value = geoJsonFile
  146 + registerMap(level === areaEnum.COUNTRY ? name : code, { geoJSON: geoJsonFile as any, specialAreas: {} })
  147 + loading.value = false
  148 + } catch (error) {
  149 + loading.value = false
  150 + console.error('动态注册地图出错', error)
130 } 151 }
131 } 152 }
132 153
@@ -136,7 +157,7 @@ registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any @@ -136,7 +157,7 @@ registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any
136 // 进行更换初始化地图 如果为china 单独处理 157 // 进行更换初始化地图 如果为china 单独处理
137 const registerMapInitAsync = async () => { 158 const registerMapInitAsync = async () => {
138 await nextTick() 159 await nextTick()
139 - const adCode = `${props.chartConfig.option.mapRegion.adcode}` 160 + const adCode = props.chartConfig.option.mapRegion.adcode
140 if (adCode !== 'china') { 161 if (adCode !== 'china') {
141 await getGeojson(adCode) 162 await getGeojson(adCode)
142 } else { 163 } else {
@@ -147,9 +168,13 @@ const registerMapInitAsync = async () => { @@ -147,9 +168,13 @@ const registerMapInitAsync = async () => {
147 registerMapInitAsync() 168 registerMapInitAsync()
148 169
149 // 手动触发渲染 170 // 手动触发渲染
150 -const vEchartsSetOption = () => {  
151 - option.value = props.chartConfig.option  
152 - setOption(vChartRef.value, props.chartConfig.option) 171 +const vEchartsSetOption = async () => {
  172 + try {
  173 + option.value = props.chartConfig.option
  174 + setOption(vChartRef.value, props.chartConfig.option)
  175 + } catch (error) {
  176 + console.error('触发渲染出错', error)
  177 + }
153 } 178 }
154 179
155 // 更新数据处理 180 // 更新数据处理
@@ -159,7 +184,6 @@ const dataSetHandle = async (dataset: any) => { @@ -159,7 +184,6 @@ const dataSetHandle = async (dataset: any) => {
159 else if (item.type === 'map' && dataset.map) item.data = dataset.map 184 else if (item.type === 'map' && dataset.map) item.data = dataset.map
160 }) 185 })
161 if (dataset.pieces) props.chartConfig.option.visualMap.pieces = dataset.pieces 186 if (dataset.pieces) props.chartConfig.option.visualMap.pieces = dataset.pieces
162 -  
163 isPreview() && vEchartsSetOption() 187 isPreview() && vEchartsSetOption()
164 } 188 }
165 189
@@ -202,7 +226,7 @@ watch( @@ -202,7 +226,7 @@ watch(
202 226
203 //监听地图展示区域发生变化 227 //监听地图展示区域发生变化
204 watch( 228 watch(
205 - () => `${props.chartConfig.option.mapRegion.adcode}`, 229 + () => props.chartConfig.option.mapRegion.adcode,
206 async newData => { 230 async newData => {
207 try { 231 try {
208 await getGeojson(newData) 232 await getGeojson(newData)
@@ -225,17 +249,26 @@ useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => { @@ -225,17 +249,26 @@ useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
225 dataSetHandle(newData) 249 dataSetHandle(newData)
226 }) 250 })
227 251
228 -//地图点击 252 +const regionMapParentArea = {
  253 + [areaEnum.PROVINCE]: areaEnum.COUNTRY, //省份的上一级 中国
  254 + [areaEnum.CITY]: areaEnum.PROVINCE, //城市的上一级 省份
  255 + [areaEnum.COUNTY]: areaEnum.CITY, //县或者区的上一级 城市
  256 + [areaEnum.TOWN]: areaEnum.COUNTY //镇的上一级 县或者区
  257 +}
  258 +
  259 +//地图点击下钻
229 const handleVChartClick = async (params: any) => { 260 const handleVChartClick = async (params: any) => {
230 if (props.chartConfig.option.drillingIn) { 261 if (props.chartConfig.option.drillingIn) {
231 const { name } = params 262 const { name } = params
232 - saveSelectValue.value = name  
233 - const findAdcode = (cityMap as any)[name]  
234 - if (!findAdcode) return  
235 - props.chartConfig.option.mapRegion.adcode = findAdcode  
236 - historyData.value.push({  
237 - name,  
238 - code: findAdcode 263 + saveGeojson.value?.features.forEach((item: any) => {
  264 + if (item.properties.name === name) {
  265 + const level = item.properties.level.toUpperCase()
  266 + const adcode = item.properties.adcode
  267 + props.chartConfig.option.mapRegion.adcode = adcode
  268 + saveLevelStr.level = level
  269 + saveLevelStr.parentInfo.adcode = item.properties.parent.adcode //保存上一级的地区编码
  270 + saveLevelStr.parentInfo.level = (regionMapParentArea as any)[level] //保存上一级的行政级别
  271 + }
239 }) 272 })
240 } 273 }
241 } 274 }