Commit 1b052dfc269f85221389c413a577131b0dbbbf6b

Authored by fengtao
Committed by xp.Huang
1 parent 1aa17ab8

perf(src/views/chart): 优化三维地图右侧区块配置项,并且修复兼容之前旧地图

1 <script lang="ts" setup name="SelectCity"> 1 <script lang="ts" setup name="SelectCity">
2 -import { onMounted, reactive } from 'vue' 2 +import { onMounted, reactive, nextTick } from 'vue'
3 import { getAreaList } from '@/api/external/common/index' 3 import { getAreaList } from '@/api/external/common/index'
4 import { areaEnum } from '../config' 4 import { areaEnum } from '../config'
5 5
@@ -25,7 +25,8 @@ const selectValues = reactive({ @@ -25,7 +25,8 @@ 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 + levelStr: areaEnum.COUNTRY,
  29 + areaName: ''
29 }) 30 })
30 31
31 const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => { 32 const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
@@ -34,36 +35,40 @@ const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => { @@ -34,36 +35,40 @@ const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
34 parentId 35 parentId
35 }) 36 })
36 if (!resp) return [] 37 if (!resp) return []
37 - return resp.map((item: any) => ({ label: item.name, value: item.code })) 38 + return resp.map((item: Recordable) => ({ label: item.name, value: item.code }))
38 } 39 }
39 40
40 onMounted(async () => { 41 onMounted(async () => {
41 selectOptions.provinceOptions = await getAreaLists() 42 selectOptions.provinceOptions = await getAreaLists()
42 - ;(selectOptions.provinceOptions as never as any).unshift({ 43 + ;(selectOptions.provinceOptions as never as Recordable[]).unshift({
43 label: '中国', 44 label: '中国',
44 value: 'china' 45 value: 'china'
45 }) 46 })
46 - onHandleSelectProvince(props.optionData?.mapRegion.saveSelect['provinceValue']) 47 + onHandleSelectProvince(props.optionData?.mapRegion.saveSelect['provinceValue'], {})
47 for (let i in selectValues) Reflect.set(selectValues, i, props.optionData?.mapRegion.saveSelect[i]) 48 for (let i in selectValues) Reflect.set(selectValues, i, props.optionData?.mapRegion.saveSelect[i])
48 }) 49 })
49 50
50 -const onHandleSelectProvince = async (value: number | string) => { 51 +const onHandleSelectProvince = async (value: number | string, options: Recordable) => {
51 selectValues.cityValue = null 52 selectValues.cityValue = null
52 selectValues.countyValue = null 53 selectValues.countyValue = null
53 if (value === 'china') return (selectValues.levelStr = areaEnum.COUNTRY) 54 if (value === 'china') return (selectValues.levelStr = areaEnum.COUNTRY)
54 - selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value as any) 55 + selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value as number)
55 selectValues.levelStr = areaEnum.PROVINCE 56 selectValues.levelStr = areaEnum.PROVINCE
  57 + selectValues.areaName = options.label
56 } 58 }
57 59
58 -const onHandleSelectCity = async (value: number) => { 60 +const onHandleSelectCity = async (value: number, options: Recordable) => {
59 selectValues.countyValue = null 61 selectValues.countyValue = null
60 selectOptions.countryOptions = await getAreaLists(areaEnum.COUNTY, value) 62 selectOptions.countryOptions = await getAreaLists(areaEnum.COUNTY, value)
61 selectValues.levelStr = areaEnum.CITY 63 selectValues.levelStr = areaEnum.CITY
  64 + selectValues.areaName = options.label
62 } 65 }
63 66
64 -const onHandleSubmit = () => { 67 +const onHandleSubmit = async () => {
  68 + await nextTick()
65 emits('submit', selectValues) 69 emits('submit', selectValues)
66 } 70 }
  71 +
67 const resetValue = () => { 72 const resetValue = () => {
68 selectValues.provinceValue = 'china' 73 selectValues.provinceValue = 'china'
69 selectValues.cityValue = null 74 selectValues.cityValue = null
@@ -72,6 +77,7 @@ const resetValue = () => { @@ -72,6 +77,7 @@ const resetValue = () => {
72 selectOptions.cityOptions = [] 77 selectOptions.cityOptions = []
73 selectOptions.countryOptions = [] 78 selectOptions.countryOptions = []
74 } 79 }
  80 +
75 defineExpose({ 81 defineExpose({
76 resetValue 82 resetValue
77 }) 83 })
@@ -20,6 +20,7 @@ export interface regionInfo { @@ -20,6 +20,7 @@ export interface regionInfo {
20 cityValue: string | null 20 cityValue: string | null
21 countyValue: string | null 21 countyValue: string | null
22 levelStr: areaEnum 22 levelStr: areaEnum
  23 + areaName: string
23 } 24 }
24 25
25 type itemOption = { 26 type itemOption = {
@@ -36,6 +37,7 @@ export interface regionOption { @@ -36,6 +37,7 @@ export interface regionOption {
36 export interface historyParentType { 37 export interface historyParentType {
37 adcode: number 38 adcode: number
38 level: string 39 level: string
  40 + areaName: string
39 } 41 }
40 42
41 export interface backMapLevel { 43 export interface backMapLevel {
@@ -50,6 +52,7 @@ export interface levelFunc { @@ -50,6 +52,7 @@ export interface levelFunc {
50 //数据源接口 52 //数据源接口
51 export interface dataPointI { 53 export interface dataPointI {
52 name: string 54 name: string
  55 + city_name: string
53 value: number[] 56 value: number[]
54 adcode: number 57 adcode: number
55 height: number 58 height: number
@@ -69,6 +72,70 @@ export const regionMapParentArea = { @@ -69,6 +72,70 @@ export const regionMapParentArea = {
69 TOWN: areaEnum.COUNTY //镇的上一级 县或者区 72 TOWN: areaEnum.COUNTY //镇的上一级 县或者区
70 } 73 }
71 74
  75 +// 缩放配置文件
  76 +export const setScale = (adcode: string | number) => {
  77 + switch (adcode) {
  78 + case 'china':
  79 + return { distance: 100, zoom: 1, alpha: 45 }
  80 + case '110000':
  81 + return { distance: 150, zoom: 0.8, alpha: 45 }
  82 + case '120000':
  83 + return { distance: 190, zoom: 0.8, alpha: 45 }
  84 + case '130000':
  85 + return { distance: 165, zoom: 0.8, alpha: 45 }
  86 + case '140000':
  87 + return { distance: 216, zoom: 0.8, alpha: 45 }
  88 + case '150000':
  89 + return { distance: 130, zoom: 0.8, alpha: 45 }
  90 + case '210000':
  91 + return { distance: 130, zoom: 0.8, alpha: 45 }
  92 + case '310000':
  93 + return { distance: 135, zoom: 0.8, alpha: 45 }
  94 + case '320000':
  95 + return { distance: 145, zoom: 0.8, alpha: 45 }
  96 + case '330000':
  97 + return { distance: 135, zoom: 0.8, alpha: 45 }
  98 + case '340000':
  99 + return { distance: 170, zoom: 0.8, alpha: 45 }
  100 + case '350000':
  101 + return { distance: 150, zoom: 0.8, alpha: 45 }
  102 + case '360000':
  103 + return { distance: 190, zoom: 0.8, alpha: 45 }
  104 + case '370000':
  105 + return { distance: 135, zoom: 0.8, alpha: 45 }
  106 + case '420000':
  107 + return { distance: 145, zoom: 0.8, alpha: 45 }
  108 + case '430000':
  109 + return { distance: 165, zoom: 0.8, alpha: 45 }
  110 + case '440000':
  111 + return { distance: 165, zoom: 0.8, alpha: 45 }
  112 + case '500000':
  113 + return { distance: 145, zoom: 0.8, alpha: 45 }
  114 + case '520000':
  115 + return { distance: 135, zoom: 0.8, alpha: 45 }
  116 + case '530000':
  117 + return { distance: 145, zoom: 0.8, alpha: 45 }
  118 + case '540000':
  119 + return { distance: 140, zoom: 0.8, alpha: 45 }
  120 + case '610000':
  121 + return { distance: 210, zoom: 0.8, alpha: 45 }
  122 + case '620000':
  123 + return { distance: 135, zoom: 0.8, alpha: 45 }
  124 + case '640000':
  125 + return { distance: 195, zoom: 0.8, alpha: 45 }
  126 + case '650000':
  127 + return { distance: 135, zoom: 0.8, alpha: 45 }
  128 + case '710000':
  129 + return { distance: 135, zoom: 0.8, alpha: 45 }
  130 + case '810000':
  131 + return { distance: 145, zoom: 0.8, alpha: 45 }
  132 + case '820000':
  133 + return { distance: 240, zoom: 0.8, alpha: 45 }
  134 + default:
  135 + return { distance: 125, zoom: 1, alpha: 45 }
  136 + }
  137 +}
  138 +
72 export const includes = [] 139 export const includes = []
73 140
74 // 特殊处理安徽省的下钻 141 // 特殊处理安徽省的下钻
@@ -105,11 +172,13 @@ export const option = { @@ -105,11 +172,13 @@ export const option = {
105 mapRegion: { 172 mapRegion: {
106 adcode: 'china', 173 adcode: 'china',
107 showHainanIsLands: true, 174 showHainanIsLands: true,
  175 + areaName: '',
108 saveSelect: { 176 saveSelect: {
109 levelStr: areaEnum.COUNTRY, 177 levelStr: areaEnum.COUNTRY,
110 cityValue: null, 178 cityValue: null,
111 countyValue: null, 179 countyValue: null,
112 - provinceValue: 'china' 180 + provinceValue: 'china',
  181 + areaName: ''
113 } 182 }
114 }, 183 },
115 tooltip: { 184 tooltip: {
@@ -118,30 +187,30 @@ export const option = { @@ -118,30 +187,30 @@ export const option = {
118 //三维地图有两种,一种是geo3D,另一种是map3D,但是如果使用geo3D,地图点击获取不到点击区域name 187 //三维地图有两种,一种是geo3D,另一种是map3D,但是如果使用geo3D,地图点击获取不到点击区域name
119 geo3D: { 188 geo3D: {
120 show: false, // 隐藏该层,为true时会导致出现两个地图 189 show: false, // 隐藏该层,为true时会导致出现两个地图
121 - map: 'centerMap', 190 + map: '',
122 roam: true 191 roam: true
123 }, 192 },
124 series: [ 193 series: [
125 { 194 {
126 type: 'map3D', 195 type: 'map3D',
127 - map: 'centerMap',  
128 - name: 'centerMap',  
129 - regionHeight: 3, 196 + map: '',
  197 + name: '',
  198 + regionHeight: 0,
130 label: { 199 label: {
131 show: true, 200 show: true,
132 formatter: function (params: Recordable) { 201 formatter: function (params: Recordable) {
133 return params.data.name ? params.data.name : ' ' 202 return params.data.name ? params.data.name : ' '
134 }, 203 },
135 textStyle: { 204 textStyle: {
136 - color: '#fff', 205 + color: '#ffffffff',
137 fontSize: 14 206 fontSize: 14
138 } 207 }
139 }, 208 },
140 itemStyle: { 209 itemStyle: {
141 - color: '#4482B1FF', //背景颜色 210 + color: '#3c7effff', //背景颜色
142 opacity: 1, 211 opacity: 1,
143 borderWidth: 0.8, 212 borderWidth: 0.8,
144 - borderColor: '#4482B1FF' 213 + borderColor: '#51d6a9FF'
145 }, 214 },
146 emphasis: { 215 emphasis: {
147 // 鼠标hover 高亮时图形和标签的样式 (当鼠标放上去时 label和itemStyle 的样式) 216 // 鼠标hover 高亮时图形和标签的样式 (当鼠标放上去时 label和itemStyle 的样式)
@@ -149,12 +218,12 @@ export const option = { @@ -149,12 +218,12 @@ export const option = {
149 // label高亮时的配置 218 // label高亮时的配置
150 show: true, 219 show: true,
151 textStyle: { 220 textStyle: {
152 - color: 'green', 221 + color: '#57c3c2ff',
153 fontSize: 14 222 fontSize: 14
154 } 223 }
155 }, 224 },
156 itemStyle: { 225 itemStyle: {
157 - color: 'red' 226 + color: '#1ba784ff'
158 } 227 }
159 }, 228 },
160 data: [], 229 data: [],
@@ -163,28 +232,19 @@ export const option = { @@ -163,28 +232,19 @@ export const option = {
163 } 232 }
164 }, 233 },
165 { 234 {
166 - name: 'scatter3D',  
167 - type: 'scatter3D',  
168 - coordinateSystem: 'geo3D',  
169 - symbol: 'circle',  
170 - symbolSize: 20,  
171 - animation: true,  
172 - data: []  
173 - },  
174 - {  
175 name: 'bar3D', 235 name: 'bar3D',
176 type: 'bar3D', 236 type: 'bar3D',
177 coordinateSystem: 'geo3D', 237 coordinateSystem: 'geo3D',
178 // 倒角尺寸 238 // 倒角尺寸
179 bevelSize: 0, 239 bevelSize: 0,
180 - minHeight: 12, 240 + minHeight: 5,
181 shading: 'lambert', 241 shading: 'lambert',
182 barSize: 1, 242 barSize: 1,
183 itemStyle: { 243 itemStyle: {
184 color: '#4482B1FF' 244 color: '#4482B1FF'
185 }, 245 },
186 data: [] 246 data: []
187 - }, 247 + }
188 ] 248 ]
189 } 249 }
190 250
@@ -43,7 +43,7 @@ @@ -43,7 +43,7 @@
43 /> 43 />
44 <div style="height: 30px"></div> 44 <div style="height: 30px"></div>
45 <n-tag type="primary">若配置无响应,请在预览页面查看效果</n-tag> 45 <n-tag type="primary">若配置无响应,请在预览页面查看效果</n-tag>
46 - <SettingItemBox name="区块配置"> 46 + <SettingItemBox name="地图配置">
47 <SettingItem name="区域颜色"> 47 <SettingItem name="区域颜色">
48 <n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker> 48 <n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker>
49 </SettingItem> 49 </SettingItem>
@@ -126,24 +126,10 @@ @@ -126,24 +126,10 @@
126 ></n-color-picker> 126 ></n-color-picker>
127 </SettingItem> 127 </SettingItem>
128 </SettingItemBox> 128 </SettingItemBox>
129 - <SettingItemBox name="散点配置">  
130 - <SettingItem name="大小">  
131 - <n-input-number  
132 - v-model:value="seriesList[1].symbolSize"  
133 - :min="0"  
134 - :step="1"  
135 - size="small"  
136 - placeholder="请输入"  
137 - ></n-input-number>  
138 - </SettingItem>  
139 - <SettingItem name="形状">  
140 - <n-select :options="symbolOption" v-model:value="seriesList[1].symbol"></n-select>  
141 - </SettingItem>  
142 - </SettingItemBox>  
143 <SettingItemBox name="柱状配置"> 129 <SettingItemBox name="柱状配置">
144 <SettingItem name="最小高度"> 130 <SettingItem name="最小高度">
145 <n-input-number 131 <n-input-number
146 - v-model:value="seriesList[2].minHeight" 132 + v-model:value="seriesList[1].minHeight"
147 :min="0" 133 :min="0"
148 :step="1" 134 :step="1"
149 size="small" 135 size="small"
@@ -152,7 +138,7 @@ @@ -152,7 +138,7 @@
152 </SettingItem> 138 </SettingItem>
153 <SettingItem name="大小"> 139 <SettingItem name="大小">
154 <n-input-number 140 <n-input-number
155 - v-model:value="seriesList[2].barSize" 141 + v-model:value="seriesList[1].barSize"
156 :min="0" 142 :min="0"
157 :step="1" 143 :step="1"
158 size="small" 144 size="small"
@@ -161,7 +147,7 @@ @@ -161,7 +147,7 @@
161 </SettingItem> 147 </SettingItem>
162 <SettingItem name="倒角尺寸"> 148 <SettingItem name="倒角尺寸">
163 <n-input-number 149 <n-input-number
164 - v-model:value="seriesList[2].bevelSize" 150 + v-model:value="seriesList[1].bevelSize"
165 :min="0" 151 :min="0"
166 :max="1" 152 :max="1"
167 :step="0.1" 153 :step="0.1"
@@ -170,15 +156,22 @@ @@ -170,15 +156,22 @@
170 ></n-input-number> 156 ></n-input-number>
171 </SettingItem> 157 </SettingItem>
172 </SettingItemBox> 158 </SettingItemBox>
173 - <SettingItemBox name="区块配置"> 159 + </CollapseItem>
  160 + <CollapseItem name="地区配置" :expanded="true">
  161 + <SettingItemBox name="地区配置" :alone="true">
174 <template v-for="(item, map3DIndex) in optionData.dataset.map3D" :key="map3DIndex"> 162 <template v-for="(item, map3DIndex) in optionData.dataset.map3D" :key="map3DIndex">
175 - <setting-item name="地区名称">  
176 - <n-input v-model:value="item.name"> </n-input> 163 + <setting-item name="省份名称">
  164 + <n-select
  165 + @change="(v:number,o:Recordable,w:Recordable,s1:number)=> onHandleSelectProvince(v,o,item, map3DIndex)"
  166 + placeholder="请选择省份"
  167 + v-model:value="item.name"
  168 + :options="item.provinceOptions"
  169 + />
177 </setting-item> 170 </setting-item>
178 - <setting-item name="地区代码">  
179 - <n-input v-model:value="item.adcode"> </n-input> 171 + <setting-item name="城市名称">
  172 + <n-select placeholder="请选择城市" v-model:value="item.city_name" :options="item.cityOptions" />
180 </setting-item> 173 </setting-item>
181 - <setting-item name="离地高度"> 174 + <setting-item name="区块厚度">
182 <n-input-number v-model:value="item.height"> </n-input-number> 175 <n-input-number v-model:value="item.height"> </n-input-number>
183 </setting-item> 176 </setting-item>
184 <setting-item name="区块颜色"> 177 <setting-item name="区块颜色">
@@ -187,71 +180,27 @@ @@ -187,71 +180,27 @@
187 <setting-item name="区块透明度"> 180 <setting-item name="区块透明度">
188 <n-input-number v-model:value="item.itemStyle.opacity"> </n-input-number> 181 <n-input-number v-model:value="item.itemStyle.opacity"> </n-input-number>
189 </setting-item> 182 </setting-item>
  183 + <setting-item></setting-item>
190 <setting-item> 184 <setting-item>
191 <n-button size="small" @click="optionData.dataset.map3D.splice(map3DIndex, 1)"> - </n-button> 185 <n-button size="small" @click="optionData.dataset.map3D.splice(map3DIndex, 1)"> - </n-button>
192 </setting-item> 186 </setting-item>
193 </template> 187 </template>
194 - <n-button  
195 - style="float: right"  
196 - size="small"  
197 - @click="optionData.dataset.map3D.push(cloneDeep(STATIC_SCATTER_CONFIG))"  
198 - >  
199 - +  
200 - </n-button> 188 + <div class="h-space"></div>
  189 + <n-button size="small" @click="handleAddRegion"> + </n-button>
201 </SettingItemBox> 190 </SettingItemBox>
202 - <SettingItemBox name="散点配置">  
203 - <template v-for="(item, scatterIndex) in optionData.dataset.scatter3D" :key="scatterIndex">  
204 - <setting-item name="地区名称">  
205 - <n-input v-model:value="item.name"> </n-input>  
206 - </setting-item>  
207 - <setting-item name="地区代码">  
208 - <n-input v-model:value="item.adcode"> </n-input>  
209 - </setting-item>  
210 - <setting-item name="离地高度">  
211 - <n-input-number v-model:value="item.height"> </n-input-number>  
212 - </setting-item> 191 + </CollapseItem>
  192 + <CollapseItem name="柱状配置" :expanded="true">
  193 + <SettingItemBox name="柱状配置" :alone="true">
  194 + <template v-for="(item, barIndex) in optionData.dataset.bar3D" :key="barIndex">
213 <setting-item name="经度"> 195 <setting-item name="经度">
214 <n-input-number v-model:value="item.value[0]"> </n-input-number> 196 <n-input-number v-model:value="item.value[0]"> </n-input-number>
215 </setting-item> 197 </setting-item>
216 <setting-item name="纬度"> 198 <setting-item name="纬度">
217 <n-input-number v-model:value="item.value[1]"> </n-input-number> 199 <n-input-number v-model:value="item.value[1]"> </n-input-number>
218 </setting-item> 200 </setting-item>
219 - <setting-item name="散点颜色">  
220 - <n-color-picker size="small" :modes="['hex']" v-model:value="item.itemStyle.color"></n-color-picker>  
221 - </setting-item>  
222 - <setting-item name="散点透明度">  
223 - <n-input-number v-model:value="item.itemStyle.opacity"> </n-input-number>  
224 - </setting-item>  
225 - <setting-item> </setting-item>  
226 - <setting-item>  
227 - <n-button size="small" @click="optionData.dataset.scatter3D.splice(scatterIndex, 1)"> - </n-button>  
228 - </setting-item>  
229 - </template>  
230 - <n-button  
231 - style="float: right"  
232 - size="small"  
233 - @click="optionData.dataset.scatter3D.push(cloneDeep(STATIC_SCATTER_CONFIG))"  
234 - >  
235 - +  
236 - </n-button>  
237 - </SettingItemBox>  
238 - <SettingItemBox name="柱状配置">  
239 - <template v-for="(item, barIndex) in optionData.dataset.bar3D" :key="barIndex">  
240 - <setting-item name="地区名称">  
241 - <n-input v-model:value="item.name"> </n-input>  
242 - </setting-item>  
243 - <setting-item name="地区代码">  
244 - <n-input v-model:value="item.adcode"> </n-input>  
245 - </setting-item>  
246 <setting-item name="离地高度"> 201 <setting-item name="离地高度">
247 <n-input-number v-model:value="item.height"> </n-input-number> 202 <n-input-number v-model:value="item.height"> </n-input-number>
248 </setting-item> 203 </setting-item>
249 - <setting-item name="经度">  
250 - <n-input-number v-model:value="item.value[0]"> </n-input-number>  
251 - </setting-item>  
252 - <setting-item name="纬度">  
253 - <n-input-number v-model:value="item.value[1]"> </n-input-number>  
254 - </setting-item>  
255 <setting-item name="柱状颜色"> 204 <setting-item name="柱状颜色">
256 <n-color-picker size="small" :modes="['hex']" v-model:value="item.itemStyle.color"></n-color-picker> 205 <n-color-picker size="small" :modes="['hex']" v-model:value="item.itemStyle.color"></n-color-picker>
257 </setting-item> 206 </setting-item>
@@ -262,6 +211,7 @@ @@ -262,6 +211,7 @@
262 <n-button size="small" @click="optionData.dataset.bar3D.splice(barIndex, 1)"> - </n-button> 211 <n-button size="small" @click="optionData.dataset.bar3D.splice(barIndex, 1)"> - </n-button>
263 </setting-item> 212 </setting-item>
264 </template> 213 </template>
  214 + <div class="h-space"></div>
265 <n-button 215 <n-button
266 style="float: right" 216 style="float: right"
267 size="small" 217 size="small"
@@ -274,13 +224,15 @@ @@ -274,13 +224,15 @@
274 </template> 224 </template>
275 225
276 <script setup lang="ts"> 226 <script setup lang="ts">
277 -import { PropType, computed, ref } from 'vue' 227 +import { PropType, computed, ref, onMounted } from 'vue'
278 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' 228 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
279 import { GlobalThemeJsonType } from '@/settings/chartThemes/index' 229 import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
280 import { GlobalSetting } from '@/components/Pages/ChartItemSetting' 230 import { GlobalSetting } from '@/components/Pages/ChartItemSetting'
281 import SelectCity from './components/SelectCity.vue' 231 import SelectCity from './components/SelectCity.vue'
282 import { regionInfo } from './config' 232 import { regionInfo } from './config'
283 import { cloneDeep } from 'lodash' 233 import { cloneDeep } from 'lodash'
  234 +import { getAreaList } from '@/api/external/common/index'
  235 +import { areaEnum } from '../../../Decorates/Mores/Weather/config'
284 236
285 const props = defineProps({ 237 const props = defineProps({
286 optionData: { 238 optionData: {
@@ -293,67 +245,83 @@ const seriesList = computed(() => { @@ -293,67 +245,83 @@ const seriesList = computed(() => {
293 return props.optionData.series 245 return props.optionData.series
294 }) 246 })
295 247
  248 +const datasetMap3DList = computed(() => {
  249 + return props.optionData.dataset['map3D']
  250 +})
  251 +
296 const STATIC_SCATTER_CONFIG = { 252 const STATIC_SCATTER_CONFIG = {
297 - name: '', 253 + name: null,
  254 + adcode: 510000,
  255 + city_name:null,
298 value: [0, 0, 0], 256 value: [0, 0, 0],
299 - adcode: 0,  
300 - height: 0, 257 + height: 2,
301 itemStyle: { 258 itemStyle: {
302 - color: '', 259 + color: '#4482B1FF',
303 opacity: 1 260 opacity: 1
304 } 261 }
305 } 262 }
306 263
307 -const symbolOption = ref([  
308 - {  
309 - label: 'circle',  
310 - value: 'circle'  
311 - },  
312 - {  
313 - label: 'rect',  
314 - value: 'rect'  
315 - },  
316 - {  
317 - label: 'roundRect',  
318 - value: 'roundRect'  
319 - },  
320 - {  
321 - label: 'triangle',  
322 - value: 'triangle'  
323 - },  
324 - {  
325 - label: 'diamond',  
326 - value: 'diamond'  
327 - },  
328 - {  
329 - label: 'pin',  
330 - value: 'pin'  
331 - },  
332 - {  
333 - label: 'arrow',  
334 - value: 'arrow'  
335 - },  
336 - {  
337 - label: 'none',  
338 - value: 'none'  
339 - }  
340 -])  
341 -  
342 const SelectCityRef = ref<InstanceType<typeof SelectCity>>() 264 const SelectCityRef = ref<InstanceType<typeof SelectCity>>()
343 265
  266 +const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
  267 + const resp = await getAreaList({
  268 + level,
  269 + parentId
  270 + })
  271 + if (!resp) return []
  272 + return resp.map((item: Recordable) => ({ label: item.name, value: item.name, adcode: item.code }))
  273 +}
  274 +
  275 +onMounted(async () => {
  276 + datasetMap3DList.value.forEach(async (item: Recordable) => {
  277 + item.provinceOptions = await getAreaLists()
  278 + item.cityOptions = await getAreaLists(areaEnum.CITY, !item.adcode ? mapRegionCache.value.adcode : item.adcode)
  279 + item.adcode = !item.adcode ? mapRegionCache.value.adcode : item.adcode
  280 + })
  281 +})
  282 +
  283 +const onHandleSelectProvince = async (value: number, option: Recordable, item: Recordable, mapIndex: number) => {
  284 + const findIndex = datasetMap3DList.value.findIndex((findItem: Recordable) => findItem.name === item.name)
  285 + datasetMap3DList.value[findIndex].city_name = null
  286 + datasetMap3DList.value[findIndex].adcode = option.adcode
  287 + datasetMap3DList.value[findIndex].cityOptions = await getAreaLists(areaEnum.CITY, option.adcode)
  288 +}
  289 +
  290 +const handleAddRegion = () => {
  291 + props.optionData.dataset.map3D.push(cloneDeep(STATIC_SCATTER_CONFIG))
  292 + datasetMap3DList.value.forEach(async (item: Recordable) => {
  293 + item.provinceOptions = await getAreaLists()
  294 + })
  295 +}
  296 +
  297 +const mapRegionCache = computed(() => {
  298 + return props.optionData.mapRegion
  299 +})
  300 +
344 const onHandleSelectValues = (values: regionInfo) => { 301 const onHandleSelectValues = (values: regionInfo) => {
345 - const { cityValue, countyValue, provinceValue } = values  
346 - props.optionData.mapRegion.saveSelect = values  
347 - props.optionData.mapRegion.adcode = countyValue 302 + const { cityValue, countyValue, provinceValue, areaName } = values
  303 + mapRegionCache.value.areaName = areaName
  304 + mapRegionCache.value.saveSelect = values
  305 + mapRegionCache.value.adcode = countyValue
348 ? countyValue 306 ? countyValue
349 : cityValue 307 : cityValue
350 ? cityValue 308 ? cityValue
351 : provinceValue === 'china' 309 : provinceValue === 'china'
352 ? 'china' 310 ? 'china'
353 : provinceValue 311 : provinceValue
  312 + props.optionData.mapRegion = mapRegionCache.value
354 } 313 }
355 314
356 const handleChangeDrillingIn = () => { 315 const handleChangeDrillingIn = () => {
357 SelectCityRef.value?.resetValue() 316 SelectCityRef.value?.resetValue()
  317 + props.optionData.mapRegion.adcode = 'china'
  318 + props.optionData.mapRegion.areaName = ''
  319 + props.optionData.mapRegion.saveSelect.areaName = ''
358 } 320 }
359 </script> 321 </script>
  322 +
  323 +<style scoped>
  324 +.h-space {
  325 + height: 10px;
  326 +}
  327 +</style>
@@ -2,37 +2,9 @@ @@ -2,37 +2,9 @@
2 "map3D": [ 2 "map3D": [
3 { 3 {
4 "name": "四川省", 4 "name": "四川省",
5 - "height": 5,  
6 - "adcode": "510000",  
7 - "itemStyle": {  
8 - "color": "#4482B1FF",  
9 - "opacity": 1,  
10 - "borderWidth": 0.4,  
11 - "borderColor": "#5F9EA0"  
12 - }  
13 - },  
14 - {  
15 - "name": "山西省",  
16 - "height": 6,  
17 - "adcode": "140000",  
18 - "itemStyle": {  
19 - "color": "#4482B1FF",  
20 - "opacity": 1,  
21 - "borderWidth": 0.4,  
22 - "borderColor": "#5F9EA0"  
23 - }  
24 - }  
25 - ],  
26 - "scatter3D": [  
27 - {  
28 - "name": "广东省",  
29 - "value": [  
30 - 113.2592945,  
31 - 23.1301964,  
32 - 20000  
33 - ],  
34 - "adcode": "440000",  
35 - "height": 5, 5 + "adcode": 510000,
  6 + "city_name": "成都市",
  7 + "height": 2,
36 "itemStyle": { 8 "itemStyle": {
37 "color": "#4482B1FF", 9 "color": "#4482B1FF",
38 "opacity": 1, 10 "opacity": 1,
@@ -43,14 +15,12 @@ @@ -43,14 +15,12 @@
43 ], 15 ],
44 "bar3D": [ 16 "bar3D": [
45 { 17 {
46 - "name": "安徽省",  
47 "value": [ 18 "value": [
48 117.283042, 19 117.283042,
49 31.86119, 20 31.86119,
50 20000 21 20000
51 ], 22 ],
52 - "adcode": "340000",  
53 - "height": 5, 23 + "height": 2,
54 "itemStyle": { 24 "itemStyle": {
55 "color": "#4482B1FF", 25 "color": "#4482B1FF",
56 "opacity": 1, 26 "opacity": 1,
@@ -59,4 +29,4 @@ @@ -59,4 +29,4 @@
59 } 29 }
60 } 30 }
61 ] 31 ]
62 -}  
  32 +}
@@ -20,10 +20,12 @@ import config, { @@ -20,10 +20,12 @@ import config, {
20 backMapLevel, 20 backMapLevel,
21 levelFunc, 21 levelFunc,
22 regionMapParentArea, 22 regionMapParentArea,
23 - specialTreatmentAnhui 23 + specialTreatmentAnhui,
  24 + setScale
24 } from './config' 25 } from './config'
25 import { getGeoJsonMap } from '@/api/external/common' 26 import { getGeoJsonMap } from '@/api/external/common'
26 import { ThreeMapEnum } from '@/enums/external/mapEnum' 27 import { ThreeMapEnum } from '@/enums/external/mapEnum'
  28 +import cloneDeep from 'lodash/cloneDeep'
27 29
28 const props = defineProps({ 30 const props = defineProps({
29 chartConfig: { 31 chartConfig: {
@@ -115,13 +117,14 @@ props.chartConfig.option = { @@ -115,13 +117,14 @@ props.chartConfig.option = {
115 117
116 //地图点击返回 118 //地图点击返回
117 const handleBack = async () => { 119 const handleBack = async () => {
  120 + stopWatch()
118 if (drillingIn.value) { 121 if (drillingIn.value) {
119 //如果是从右边配置里设置的,比如点击四川省,然后点击返回 122 //如果是从右边配置里设置的,比如点击四川省,然后点击返回
120 const savePopParent = saveHistoryParent.value.pop() 123 const savePopParent = saveHistoryParent.value.pop()
121 let saveAdcode = savePopParent?.adcode as string | number 124 let saveAdcode = savePopParent?.adcode as string | number
122 saveLevelStr.level = savePopParent?.level as string 125 saveLevelStr.level = savePopParent?.level as string
123 if (!savePopParent) { 126 if (!savePopParent) {
124 - saveAdcode = getParentAdcode(mapRegion.value.adcode) 127 + saveAdcode = getParentAdcode(mapRegion.value.adcode).adcodeNum
125 saveLevelStr.level = (regionMapParentArea as Recordable)[mapRegion.value.saveSelect.levelStr] 128 saveLevelStr.level = (regionMapParentArea as Recordable)[mapRegion.value.saveSelect.levelStr]
126 } 129 }
127 if (saveAdcode === 0) { 130 if (saveAdcode === 0) {
@@ -132,6 +135,7 @@ const handleBack = async () => { @@ -132,6 +135,7 @@ const handleBack = async () => {
132 const adcode = saveAdcode === 100000 ? 'china' : saveAdcode 135 const adcode = saveAdcode === 100000 ? 'china' : saveAdcode
133 saveClickRegion.value.level = saveLevelStr.level 136 saveClickRegion.value.level = saveLevelStr.level
134 if (exist) { 137 if (exist) {
  138 + mapRegion.value.areaName = getParentAdcode(mapRegion.value.adcode).areaName
135 //fix 解决点击下钻返回后页面为空问题 139 //fix 解决点击下钻返回后页面为空问题
136 mapRegion.value.adcode = adcode 140 mapRegion.value.adcode = adcode
137 } 141 }
@@ -142,20 +146,24 @@ const handleBack = async () => { @@ -142,20 +146,24 @@ const handleBack = async () => {
142 const handleMap3DClick = async (params: Recordable) => { 146 const handleMap3DClick = async (params: Recordable) => {
143 if (drillingIn.value) { 147 if (drillingIn.value) {
144 const { name } = params 148 const { name } = params
145 - saveGeojson.value?.features.forEach((item: Recordable) => { 149 + const geoJson = JSON.parse(saveGeojson.value?.geoJson)
  150 + geoJson?.features.forEach((item: Recordable) => {
146 if (item.properties.name === name) { 151 if (item.properties.name === name) {
147 const level = item.properties.level.toUpperCase() 152 const level = item.properties.level.toUpperCase()
148 const adcode = item.properties.adcode 153 const adcode = item.properties.adcode
  154 + const areaName = item.properties.name
149 if (level === 'DISTRICT') return //下钻暂且不支持地区 155 if (level === 'DISTRICT') return //下钻暂且不支持地区
150 if (String(adcode).startsWith('15') && level === areaEnum.CITY) return //特殊处理地区码15开头的 156 if (String(adcode).startsWith('15') && level === areaEnum.CITY) return //特殊处理地区码15开头的
151 mapRegion.value.adcode = adcode 157 mapRegion.value.adcode = adcode
  158 + mapRegion.value.areaName = areaName
152 saveClickRegion.value.level = level 159 saveClickRegion.value.level = level
153 saveLevelStr.level = level 160 saveLevelStr.level = level
154 saveHistoryParent.value.push({ 161 saveHistoryParent.value.push({
155 adcode: specialTreatmentAnhui.includes(item.properties.name) 162 adcode: specialTreatmentAnhui.includes(item.properties.name)
156 ? JSON.parse(item.properties.parent)?.adcode 163 ? JSON.parse(item.properties.parent)?.adcode
157 : item.properties.parent.adcode, 164 : item.properties.parent.adcode,
158 - level: (regionMapParentArea as Recordable)[level] 165 + level: (regionMapParentArea as Recordable)[level],
  166 + areaName: saveGeojson.value.name
159 }) 167 })
160 } 168 }
161 }) 169 })
@@ -182,18 +190,22 @@ const getGeojson = (regionId: number | string) => { @@ -182,18 +190,22 @@ const getGeojson = (regionId: number | string) => {
182 regionId === 'china' ? chinaDefaultRegionId.value : regionId, 190 regionId === 'china' ? chinaDefaultRegionId.value : regionId,
183 !saveLevelStr.level ? levelStr : saveLevelStr.level //没有则获取右侧配置的行政级别 191 !saveLevelStr.level ? levelStr : saveLevelStr.level //没有则获取右侧配置的行政级别
184 ).then(res => { 192 ).then(res => {
185 - const { geoJson, name, code, level } = res.data 193 + saveGeojson.value = res.data //保存一份服务端返回的数据
  194 + const { geoJson, name, level, code } = res.data
186 const geoJsonFile = JSON.parse(geoJson) 195 const geoJsonFile = JSON.parse(geoJson)
187 if (!geoJsonFile) return 196 if (!geoJsonFile) return
188 - saveGeojson.value = geoJsonFile //保存一份服务端返回的geojson  
189 const nameChina = name === '中国' ? 'china' : name //为中国的话,registerMap第一个必须是china,否则显示不出来 197 const nameChina = name === '中国' ? 'china' : name //为中国的话,registerMap第一个必须是china,否则显示不出来
190 /** 198 /**
191 * 主要注意的点,registerMap中的第一个参数需要和series中的map匹配,否则渲染不出地图, 199 * 主要注意的点,registerMap中的第一个参数需要和series中的map匹配,否则渲染不出地图,
192 * 比如map: '北京市' echarts.registerMap('北京市', beijingGeoJSON); 200 * 比如map: '北京市' echarts.registerMap('北京市', beijingGeoJSON);
193 */ 201 */
194 - registerMap(level === areaEnum.COUNTRY ? nameChina : code, { geoJSON: geoJsonFile, specialAreas: {} }) //注册geoJSON 202 + registerMap(level === areaEnum.COUNTRY ? nameChina : !mapRegion.value.areaName ? code : name, {
  203 + geoJSON: geoJsonFile,
  204 + specialAreas: {}
  205 + }) //注册geoJSON
195 resolve(true) 206 resolve(true)
196 show.value = false 207 show.value = false
  208 + changeOption.value = true
197 }) 209 })
198 }) 210 })
199 } catch (error) { 211 } catch (error) {
@@ -210,12 +222,15 @@ registerMap(mapRegion.value.adcode, { geoJSON: {} as any, specialAreas: {} }) @@ -210,12 +222,15 @@ registerMap(mapRegion.value.adcode, { geoJSON: {} as any, specialAreas: {} })
210 //传adcode 获取上级 222 //传adcode 获取上级
211 const getParentAdcode = (adcode: number) => { 223 const getParentAdcode = (adcode: number) => {
212 let adcodeNum = 100000 224 let adcodeNum = 100000
213 - saveGeojson.value?.features.forEach((item: Recordable) => { 225 + let areaName = ''
  226 + const geoJson = JSON.parse(saveGeojson.value?.geoJson)
  227 + geoJson.features.forEach((item: Recordable) => {
214 if (item.properties.adcode === adcode) { 228 if (item.properties.adcode === adcode) {
215 adcodeNum = item.properties.parent.adcode 229 adcodeNum = item.properties.parent.adcode
  230 + areaName = saveGeojson.value.name
216 } 231 }
217 }) 232 })
218 - return adcodeNum 233 + return { adcodeNum, areaName }
219 } 234 }
220 235
221 // 初始化三维地图 236 // 初始化三维地图
@@ -224,7 +239,7 @@ const initMap3D = async () => { @@ -224,7 +239,7 @@ const initMap3D = async () => {
224 await nextTick() 239 await nextTick()
225 await getGeojson(mapRegion.value.adcode) 240 await getGeojson(mapRegion.value.adcode)
226 await nextTick().then(() => { 241 await nextTick().then(() => {
227 - handleRegisterMapNameAndData(mapRegion.value.adcode, dataset.value) 242 + handleRegisterMapNameAndData(mapRegion.value.adcode, dataset.value, 'china')
228 }) 243 })
229 chartInstance.value?.on('click', (e: Recordable) => { 244 chartInstance.value?.on('click', (e: Recordable) => {
230 if (!e) return 245 if (!e) return
@@ -235,16 +250,13 @@ const initMap3D = async () => { @@ -235,16 +250,13 @@ const initMap3D = async () => {
235 onMounted(() => initMap3D()) 250 onMounted(() => initMap3D())
236 251
237 // 动态注册 series中的map必须和registerMap的第一个参数匹配,否则渲染不出 252 // 动态注册 series中的map必须和registerMap的第一个参数匹配,否则渲染不出
238 -const handleRegisterMapNameAndData = (adcode: string | number, data: Recordable) => {  
239 - geo3D.value.map = adcode // coordinateSystem使用了geo3D,不能删除这一行 253 +const handleRegisterMapNameAndData = (adcode: string | number, data: Recordable, areaName: string) => {
  254 + geo3D.value.map = !areaName ? adcode : areaName // coordinateSystem使用了geo3D,不能删除这一行
240 series.value.forEach((item: Recordable) => { 255 series.value.forEach((item: Recordable) => {
241 if (item.type === ThreeMapEnum.MAP3D) { 256 if (item.type === ThreeMapEnum.MAP3D) {
242 - item.map = adcode 257 + item.map = !areaName ? adcode : areaName
243 item.data = data[ThreeMapEnum.MAP3D] 258 item.data = data[ThreeMapEnum.MAP3D]
244 } 259 }
245 - if (item.type === ThreeMapEnum.SCATTER3D) {  
246 - item.data = data[ThreeMapEnum.SCATTER3D]  
247 - }  
248 if (item.type === ThreeMapEnum.BAR3D) { 260 if (item.type === ThreeMapEnum.BAR3D) {
249 item.data = data[ThreeMapEnum.BAR3D] 261 item.data = data[ThreeMapEnum.BAR3D]
250 } 262 }
@@ -274,18 +286,27 @@ watch( @@ -274,18 +286,27 @@ watch(
274 ) 286 )
275 287
276 //处理数据标点 288 //处理数据标点
277 -const handleDataPoint = (newData: string | number) => { 289 +const handleDataPoint = (newData: string | number, areaName: string) => {
278 if (newData === 'china') { 290 if (newData === 'china') {
279 // 全国则展示所有的标点 291 // 全国则展示所有的标点
280 - handleRegisterMapNameAndData(newData, dataset.value) 292 + handleRegisterMapNameAndData(newData, dataset.value, 'china')
281 } else { 293 } else {
282 // 展示对应区域的标点 294 // 展示对应区域的标点
283 series.value.forEach((item: Recordable) => { 295 series.value.forEach((item: Recordable) => {
284 if (item.type === ThreeMapEnum.MAP3D) { 296 if (item.type === ThreeMapEnum.MAP3D) {
285 - item.data = [] //置空,否则鼠标移上去点击不了,不知道原因!  
286 - }  
287 - if (item.type === ThreeMapEnum.SCATTER3D) {  
288 - item.data = dataset.value[ThreeMapEnum.SCATTER3D].filter((dataItem: dataPointI) => dataItem.adcode === newData) 297 + item.map = !areaName ? newData : areaName
  298 + item.data = dataset.value[ThreeMapEnum.MAP3D].filter((dataItem: dataPointI) => {
  299 + if (String(dataItem.adcode) === String(!areaName ? newData : areaName)) {
  300 + return dataItem
  301 + } else if (dataItem.name === String(!areaName ? newData : areaName)) {
  302 + return dataItem
  303 + }
  304 + })
  305 + const cloneDeepData = cloneDeep(item.data)
  306 + cloneDeepData.forEach((item: dataPointI) => {
  307 + item.name = item.city_name
  308 + })
  309 + item.data = cloneDeepData.filter((item: Recordable) => item.name !== null) || []
289 } 310 }
290 if (item.type === ThreeMapEnum.BAR3D) { 311 if (item.type === ThreeMapEnum.BAR3D) {
291 item.data = dataset.value[ThreeMapEnum.BAR3D].filter((dataItem: dataPointI) => dataItem.adcode === newData) 312 item.data = dataset.value[ThreeMapEnum.BAR3D].filter((dataItem: dataPointI) => dataItem.adcode === newData)
@@ -293,22 +314,56 @@ const handleDataPoint = (newData: string | number) => { @@ -293,22 +314,56 @@ const handleDataPoint = (newData: string | number) => {
293 }) 314 })
294 } 315 }
295 } 316 }
  317 +const changeOption = ref(false)
296 318
297 // 监听地图展示区域发生变化 319 // 监听地图展示区域发生变化
298 watch( 320 watch(
299 () => `${props.chartConfig.option.mapRegion.adcode}`, 321 () => `${props.chartConfig.option.mapRegion.adcode}`,
300 - async (newData: string | number) => { 322 + async (newData: number | string) => {
301 try { 323 try {
302 await getGeojson(newData) 324 await getGeojson(newData)
303 - handleRegisterMapNameAndData(newData, dataset.value)  
304 - handleDataPoint(newData)  
305 - handleSetOption(chartInstance.value!, props.chartConfig.option) 325 + const { distance, zoom, alpha } = setScale(String(newData))
  326 + const option = props.chartConfig.option
  327 + // 修复缩放
  328 + const { series } = option || {}
  329 + series?.forEach((item: Recordable) => {
  330 + if (item.type === 'map3D') {
  331 + item.viewControl = {
  332 + ...item?.viewControl,
  333 + distance,
  334 + zoom,
  335 + alpha
  336 + }
  337 + }
  338 + })
  339 + handleRegisterMapNameAndData(newData, dataset.value, mapRegion.value.areaName)
  340 + handleDataPoint(newData, mapRegion.value.areaName)
  341 + changeOption.value = true
  342 + handleSetOption(chartInstance.value!, { ...option, series })
306 } catch (error) { 343 } catch (error) {
307 console.error('展示区域发生变化出错,出错原因->', error) 344 console.error('展示区域发生变化出错,出错原因->', error)
308 } 345 }
309 }, 346 },
310 { 347 {
311 - immediate: true 348 + immediate: true,
  349 + deep: true
  350 + }
  351 +)
  352 +
  353 +// 实时监听地图右侧配置项变化
  354 +const stopWatch = watch(
  355 + props.chartConfig.option,
  356 + async newData => {
  357 + try {
  358 + if (changeOption.value) {
  359 + // handleSetOption(chartInstance.value!, newData)
  360 + }
  361 + } catch (error) {
  362 + console.error('监听地图右侧配置项变化,出错原因->', error)
  363 + }
  364 + },
  365 + {
  366 + deep: true
312 } 367 }
313 ) 368 )
314 </script> 369 </script>