Commit e268d6d0c39f5f384600e630570b00b43c5dd108
Merge branch 'ft' into 'main_dev'
feat(src/packages): 优化三维模型拖动时,webgl上下文丢失问题 See merge request yunteng/thingskit-view!134
Showing
24 changed files
with
193 additions
and
176 deletions
... | ... | @@ -111,7 +111,7 @@ export const getVideoUrl = (id: string) => |
111 | 111 | }) |
112 | 112 | |
113 | 113 | //获取行政区域 |
114 | -export const getGeoJsonMap = (code: number, level: string) => | |
114 | +export const getGeoJsonMap = (code: number | string, level: string) => | |
115 | 115 | defHttp.get({ |
116 | 116 | url: `${Api.GEOJSONURL}${code}/${level}` |
117 | 117 | }) | ... | ... |
... | ... | @@ -14,6 +14,26 @@ export const enum areaEnum { |
14 | 14 | TOWN = 'TOWN' //镇 |
15 | 15 | } |
16 | 16 | |
17 | +//父级地区编码和级别接口 | |
18 | +export interface HistoryParentType { | |
19 | + adcode: string | number | |
20 | + level: string | |
21 | +} | |
22 | + | |
23 | +//数据源接口 | |
24 | +export interface dataPointI { | |
25 | + name: string | |
26 | + value: number[] | |
27 | + adcode: number | |
28 | + height: number | |
29 | + itemStyle: { | |
30 | + color: string | |
31 | + opacity: number | |
32 | + borderWidth: number | |
33 | + borderColor: string | |
34 | + } | |
35 | +} | |
36 | + | |
17 | 37 | export const includes = [] |
18 | 38 | |
19 | 39 | export const option = { |
... | ... | @@ -41,6 +61,9 @@ export const option = { |
41 | 61 | emphasis: { |
42 | 62 | label: { |
43 | 63 | show: true, |
64 | + formatter: function (params: Recordable) { | |
65 | + return params.data.name ? params.data.name : ' ' | |
66 | + }, | |
44 | 67 | textStyle: { |
45 | 68 | color: '#000', |
46 | 69 | fontSize: 14 |
... | ... | @@ -59,6 +82,9 @@ export const option = { |
59 | 82 | regionHeight: 3, |
60 | 83 | label: { |
61 | 84 | show: true, |
85 | + formatter: function (params: Recordable) { | |
86 | + return params.data.name ? params.data.name : ' ' | |
87 | + }, | |
62 | 88 | textStyle: { |
63 | 89 | color: '#fff', |
64 | 90 | fontSize: 14 | ... | ... |
... | ... | @@ -12,7 +12,7 @@ import { onMounted, ref, nextTick, PropType, toRefs, watch, reactive } from 'vue |
12 | 12 | import * as echarts from 'echarts' |
13 | 13 | import { registerMap } from 'echarts/core' |
14 | 14 | import 'echarts-gl' |
15 | -import config, { areaEnum } from './config' | |
15 | +import config, { areaEnum, dataPointI, HistoryParentType } from './config' | |
16 | 16 | import { getGeoJsonMap } from '@/api/external/common' |
17 | 17 | import dataMaps from './data.json' |
18 | 18 | |
... | ... | @@ -73,28 +73,26 @@ props.chartConfig.option = { |
73 | 73 | |
74 | 74 | //地图点击返回 |
75 | 75 | const watchAdcode = async () => { |
76 | + stopWatch() | |
76 | 77 | if (props.chartConfig.option.drillingIn) { |
77 | 78 | //如果是从右边配置里设置的,比如点击四川省,然后点击返回 |
78 | 79 | const savePopParent = saveHistoryParent.value.pop() |
79 | - let saveAdcode: any = savePopParent?.adcode | |
80 | - saveLevelStr.level = savePopParent?.level as string | |
80 | + let saveAdcode = savePopParent?.adcode as string | number | |
81 | + saveLevelStr.level = savePopParent?.level | |
81 | 82 | if (!savePopParent) { |
82 | 83 | saveAdcode = getParentAdcode(props.chartConfig.option.mapRegion.adcode) |
83 | - saveLevelStr.level = (regionMapParentArea as any)[props.chartConfig.option.mapRegion.saveSelect.levelStr] | |
84 | + saveLevelStr.level = (regionMapParentArea as Recordable)[props.chartConfig.option.mapRegion.saveSelect.levelStr] | |
84 | 85 | } |
85 | 86 | if (saveAdcode === 0) { |
86 | 87 | saveAdcode = 'china' |
87 | 88 | saveLevelStr.level = 'COUNTRY' |
88 | 89 | } |
89 | - await getGeojson(saveAdcode) | |
90 | + const exist = await getGeojson(saveAdcode) | |
90 | 91 | const adcode = saveAdcode === 100000 ? 'china' : saveAdcode |
91 | - props.chartConfig.option.geo3D.map = adcode | |
92 | - props.chartConfig.option.series.forEach((item: any) => { | |
93 | - if (item.type === 'map3D') item.map = adcode | |
94 | - item.data = props.chartConfig.option.dataset | |
95 | - }) | |
96 | - handleSetOption(chartInstance.value, props.chartConfig.option) | |
97 | - handleDataPoint(adcode) | |
92 | + if (exist) { | |
93 | + //fix解决点击下钻返回后页面为空问题 | |
94 | + props.chartConfig.option.mapRegion.adcode = adcode | |
95 | + } | |
98 | 96 | } |
99 | 97 | } |
100 | 98 | |
... | ... | @@ -106,46 +104,40 @@ const regionMapParentArea = { |
106 | 104 | } |
107 | 105 | |
108 | 106 | //地图点击 |
109 | -const handleMap3DClick = async (params: any) => { | |
107 | +const handleMap3DClick = async (params: Recordable) => { | |
110 | 108 | if (props.chartConfig.option.drillingIn) { |
111 | 109 | const { name } = params |
112 | - saveGeojson.value?.features.forEach((item: any) => { | |
110 | + saveGeojson.value?.features.forEach((item: Recordable) => { | |
113 | 111 | if (item.properties.name === name) { |
114 | 112 | const level = item.properties.level.toUpperCase() |
115 | 113 | const adcode = item.properties.adcode |
116 | 114 | if (level === 'DISTRICT') return |
117 | - if(String(adcode).startsWith('15') && level===areaEnum.CITY) return | |
115 | + if (String(adcode).startsWith('15') && level === areaEnum.CITY) return | |
118 | 116 | props.chartConfig.option.mapRegion.adcode = adcode |
119 | 117 | saveLevelStr.level = level |
120 | 118 | handleDataPoint(adcode) |
121 | 119 | saveHistoryParent.value.push({ |
122 | 120 | adcode: item.properties.parent.adcode, |
123 | - level: (regionMapParentArea as any)[level] | |
121 | + level: (regionMapParentArea as Recordable)[level] | |
124 | 122 | }) |
125 | 123 | } |
126 | 124 | }) |
127 | 125 | } |
128 | 126 | } |
129 | 127 | |
130 | -const saveGeojson: any = ref({}) // 保存geojson | |
128 | +const saveGeojson: Recordable = ref({}) // 保存geojson | |
131 | 129 | |
132 | 130 | const chinaDefaultRegionId = ref(100000) //如果是china则adcode为100000 |
133 | 131 | |
134 | -const saveLevelStr = reactive({ | |
135 | - // 地区级别 | |
136 | - level: '' | |
132 | +// 保存地区级别 | |
133 | +const saveLevelStr = reactive<{ level: string | undefined }>({ | |
134 | + level: '' | |
137 | 135 | }) |
138 | 136 | |
139 | -//父级地区编码和级别接口 | |
140 | -interface HistoryParentType { | |
141 | - adcode: number | |
142 | - level: string | |
143 | -} | |
144 | - | |
145 | 137 | const saveHistoryParent = ref<HistoryParentType[]>([]) |
146 | 138 | |
147 | 139 | //动态注册地图 |
148 | -const getGeojson = (regionId: any) => { | |
140 | +const getGeojson = (regionId: number | string) => { | |
149 | 141 | try { |
150 | 142 | return new Promise<boolean>(resolve => { |
151 | 143 | const { levelStr } = props.chartConfig.option.mapRegion.saveSelect //右侧配置项获取的行政级别 |
... | ... | @@ -171,11 +163,10 @@ const getGeojson = (regionId: any) => { |
171 | 163 | } |
172 | 164 | } |
173 | 165 | |
174 | - | |
175 | 166 | //传adcode 获取上级 |
176 | 167 | const getParentAdcode = (adcode: number) => { |
177 | 168 | let adcodeNum = 100000 |
178 | - saveGeojson.value?.features.forEach((item: any) => { | |
169 | + saveGeojson.value?.features.forEach((item: Recordable) => { | |
179 | 170 | if (item.properties.adcode === adcode) { |
180 | 171 | adcodeNum = item.properties.parent.adcode |
181 | 172 | } |
... | ... | @@ -200,13 +191,13 @@ const initMap = async () => { |
200 | 191 | await nextTick().then(() => { |
201 | 192 | handleSetOption(chartInstance.value, props.chartConfig.option) |
202 | 193 | }) |
203 | - chartInstance.value.on('click', (e: any) => { | |
194 | + chartInstance.value.on('click', (e: Recordable) => { | |
204 | 195 | handleMap3DClick(e) |
205 | 196 | }) |
206 | 197 | } |
207 | 198 | |
208 | 199 | // 手动触发渲染 |
209 | -const handleSetOption = (instance: any, option: any) => { | |
200 | +const handleSetOption = (instance: any, option: Recordable) => { | |
210 | 201 | if (!instance) return |
211 | 202 | try { |
212 | 203 | instance.clear() |
... | ... | @@ -221,22 +212,22 @@ onMounted(() => { |
221 | 212 | }) |
222 | 213 | |
223 | 214 | //处理数据标点 |
224 | -const handleDataPoint = (newData: any) => { | |
215 | +const handleDataPoint = (newData: string | number) => { | |
225 | 216 | if (newData === 'china') { |
226 | 217 | props.chartConfig.option.dataset = dataMaps |
227 | 218 | } else { |
228 | - props.chartConfig.option.dataset = dataMaps.filter((item: any) => item.adcode === newData) | |
219 | + props.chartConfig.option.dataset = dataMaps.filter((item: dataPointI) => item.adcode === newData) | |
229 | 220 | } |
230 | 221 | } |
231 | 222 | |
232 | 223 | //监听地图展示区域发生变化 |
233 | 224 | watch( |
234 | 225 | () => `${props.chartConfig.option.mapRegion.adcode}`, |
235 | - async (newData: any) => { | |
226 | + async (newData: string | number) => { | |
236 | 227 | try { |
237 | 228 | await getGeojson(newData) |
238 | 229 | props.chartConfig.option.geo3D.map = newData |
239 | - props.chartConfig.option.series.forEach((item: any) => { | |
230 | + props.chartConfig.option.series.forEach((item: Recordable) => { | |
240 | 231 | if (item.type === 'map3D') { |
241 | 232 | item.map = newData |
242 | 233 | item.data = props.chartConfig.option.dataset |
... | ... | @@ -254,7 +245,7 @@ watch( |
254 | 245 | ) |
255 | 246 | |
256 | 247 | // 监听地图右侧配置项变化 |
257 | -watch( | |
248 | +const stopWatch = watch( | |
258 | 249 | props.chartConfig.option, |
259 | 250 | async newData => { |
260 | 251 | try { |
... | ... | @@ -273,7 +264,7 @@ watch( |
273 | 264 | () => props.chartConfig.option.dataset, |
274 | 265 | newData => { |
275 | 266 | try { |
276 | - props.chartConfig.option.series.forEach((item: any) => { | |
267 | + props.chartConfig.option.series.forEach((item: Recordable) => { | |
277 | 268 | if (item.type === 'map3D') { |
278 | 269 | item.data = newData |
279 | 270 | } | ... | ... |
... | ... | @@ -129,7 +129,7 @@ const loadList = async () => { |
129 | 129 | } |
130 | 130 | |
131 | 131 | const handleSubmit = () => { |
132 | - searchParams.deviceProfileIds = [searchParams.deviceProfileIds] as any | |
132 | + // searchParams.deviceProfileIds = [searchParams.deviceProfileIds] as any | |
133 | 133 | emit('searchParams', searchPage, searchParams) |
134 | 134 | handleCancel() |
135 | 135 | } | ... | ... |
... | ... | @@ -88,10 +88,11 @@ export const option = { |
88 | 88 | amapLon: 104.108689, |
89 | 89 | amapLat: 30.66176, |
90 | 90 | amapZindex: 11, |
91 | - typeMarker: '', | |
91 | + iconMarker: '1.png', | |
92 | 92 | mpBorderConfig: { |
93 | - value: 'Border01', | |
93 | + value: 'Border01' | |
94 | 94 | }, |
95 | + bgColor: 'rgba(255, 255, 255, 0.1)', | |
95 | 96 | marker: { |
96 | 97 | fillColor: '#E98984FF', |
97 | 98 | fillOpacity: 0.5, | ... | ... |
... | ... | @@ -81,8 +81,8 @@ |
81 | 81 | size="small" |
82 | 82 | placeholder="请选择您要使用的图标" |
83 | 83 | style="width: 250px" |
84 | - :value="typeMarkerValue" | |
85 | - :options="typeMarkerOptions" | |
84 | + :value="iconMarkerValue" | |
85 | + :options="iconMarkerOptions" | |
86 | 86 | :render-label="renderOption" |
87 | 87 | clearable |
88 | 88 | filterable |
... | ... | @@ -92,16 +92,6 @@ |
92 | 92 | </setting-item-box> |
93 | 93 | <setting-item-box name="弹窗选择" v-if="optionData.mapOptions.mapMarkerType === MarkerEnum.MARKER"> |
94 | 94 | <setting-item name="弹窗选择"> |
95 | - <!-- <NSelect | |
96 | - size="small" | |
97 | - placeholder="请选择您要使用的弹窗" | |
98 | - style="width: 250px" | |
99 | - :value="mapSelectBorderValue" | |
100 | - :options="mapSelectBorderOption.option" | |
101 | - @update:value="mapSelectBorderHandle" | |
102 | - clearable | |
103 | - filterable | |
104 | - /> --> | |
105 | 95 | <NSelect |
106 | 96 | size="small" |
107 | 97 | placeholder="请选择您要使用的弹窗" |
... | ... | @@ -115,11 +105,16 @@ |
115 | 105 | /> |
116 | 106 | </setting-item> |
117 | 107 | </setting-item-box> |
108 | + <setting-item-box name="弹窗背景" v-if="optionData.mapOptions.mapMarkerType === MarkerEnum.MARKER"> | |
109 | + <div style="width: 10vw"> | |
110 | + <n-color-picker :modes="['rgb']" v-model:value="optionData.mapOptions.bgColor" size="small"></n-color-picker> | |
111 | + </div> | |
112 | + </setting-item-box> | |
118 | 113 | </collapse-item> |
119 | 114 | </template> |
120 | 115 | |
121 | 116 | <script setup lang="ts"> |
122 | -import { PropType, ref, computed, h, onMounted, reactive } from 'vue' | |
117 | +import { PropType, ref, computed, h, onMounted } from 'vue' | |
123 | 118 | import { option, MarkerEnum, ThemeEnum, LangEnum, ViewModeEnum, FeaturesEnum } from './config' |
124 | 119 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' |
125 | 120 | import { NEllipsis, NImage, NSelect, NSpace, SelectOption } from 'naive-ui' |
... | ... | @@ -234,7 +229,7 @@ const featuresOptions = [ |
234 | 229 | const MarkerOptions = [ |
235 | 230 | // { |
236 | 231 | // value: MarkerEnum.CIRCLE_MARKER, |
237 | - // label: '圆形标点' | |
232 | + // label: '圆形标点' //在地图里点击无效,所以注释,有需要自行打开即可 | |
238 | 233 | // }, |
239 | 234 | { |
240 | 235 | value: MarkerEnum.MARKER, |
... | ... | @@ -246,17 +241,7 @@ const MarkerOptions = [ |
246 | 241 | } |
247 | 242 | ] |
248 | 243 | |
249 | -onMounted(() => { | |
250 | - props.optionData.mapOptions.typeMarker = getMarkerImagePath(props.optionData.mapOptions.typeMarker || 'position1.png') | |
251 | - typeMarkerValue.value = props.optionData.mapOptions.typeMarker || 'position1.png' | |
252 | - mapSelectBorderValue.value = | |
253 | - `${props.optionData.mapOptions.mpBorderConfig.value.toLocaleLowerCase()}.png` || 'border01.png' | |
254 | -}) | |
255 | - | |
256 | -const typeMarkerValue = ref<string | null>('position1.png') | |
257 | - | |
258 | -const mapSelectBorderValue = ref<string | null>('border01.png') | |
259 | - | |
244 | +/**通用函数封装 */ | |
260 | 245 | const isHref = (url: string) => { |
261 | 246 | try { |
262 | 247 | new URL(url) |
... | ... | @@ -265,81 +250,86 @@ const isHref = (url: string) => { |
265 | 250 | return false |
266 | 251 | } |
267 | 252 | } |
253 | +const renderCommonOption = (option: SelectOption, src: string) => { | |
254 | + return h(NSpace, { justify: 'space-between', style: 'padding: 0 15px; height: 28px; line-height: 28px;' }, () => [ | |
255 | + h(NImage, { | |
256 | + width: 25, | |
257 | + src, | |
258 | + previewDisabled: true, | |
259 | + style: { height: '25px' } | |
260 | + } as Recordable), | |
261 | + h(NEllipsis, null, () => option.label) | |
262 | + ]) | |
263 | +} | |
264 | +const getImagePath = (path: string, name: string) => { | |
265 | + return isHref(name) ? name : new URL(`${path}/${name}`, import.meta.url).href | |
266 | +} | |
267 | +/** */ | |
268 | + | |
269 | +/** 图标选择 */ | |
270 | +const iconMarkerValue = ref<string | null>('1.png') | |
268 | 271 | |
269 | -// import.meta.glob 这个不能封装,必须是字符串,不能通过传值传进去 | |
270 | -const typeMarkerOptions = computed(() => { | |
272 | +// import.meta.glob 这里没有封装,不能通过传值传进去 | |
273 | +const iconMarkerOptions = computed(() => { | |
271 | 274 | const pathList = import.meta.glob('./images/marker/*') |
272 | 275 | return Object.keys(pathList).map(item => { |
273 | 276 | const imgName = item.split('/').at(-1) |
274 | 277 | return { |
275 | 278 | label: imgName, |
276 | 279 | value: imgName |
277 | - } as SelectOption | |
280 | + } | |
278 | 281 | }) |
279 | 282 | }) |
280 | 283 | // |
281 | 284 | |
282 | -const getMarkerImagePath = (name: string) => { | |
283 | - return isHref(name) ? name : new URL(`./images/marker/${name}`, import.meta.url).href | |
284 | -} | |
285 | +const getMarkerImagePath = (name: string) => getImagePath('./images/marker', name) | |
285 | 286 | |
286 | -const renderOption = (option: SelectOption) => { | |
287 | - return h(NSpace, { justify: 'space-between', style: 'padding: 0 15px; height: 28px; line-height: 28px;' }, () => [ | |
288 | - h(NImage, { | |
289 | - width: 25, | |
290 | - src: getMarkerImagePath(option.value as string), | |
291 | - previewDisabled: true, | |
292 | - style: { height: '25px' } | |
293 | - } as Recordable), | |
294 | - h(NEllipsis, null, () => option.label) | |
295 | - ]) | |
296 | -} | |
287 | +const renderOption = (option: SelectOption) => renderCommonOption(option, getMarkerImagePath(option.value as string)) | |
297 | 288 | |
298 | 289 | const selectHandle = (value: string) => { |
299 | - typeMarkerValue.value = value | |
300 | - props.optionData.mapOptions.typeMarker = getMarkerImagePath(value) | |
290 | + iconMarkerValue.value = value | |
291 | + props.optionData.mapOptions.iconMarker = getMarkerImagePath(value) | |
301 | 292 | } |
293 | +/** */ | |
294 | + | |
295 | +/** 弹窗选择 */ | |
296 | +const mapSelectBorderValue = ref<string | null>('border01.png') | |
302 | 297 | |
303 | 298 | const needBorder = ['border01.png', 'border02.png', 'border03.png', 'border05.png', 'border07.png'] |
304 | 299 | |
305 | -// import.meta.glob 这个不能封装,必须是字符串,不能通过传值传进去 | |
300 | +// import.meta.glob 这里没有封装,不能通过传值传进去 | |
306 | 301 | const mapBorderOptions = computed(() => { |
307 | 302 | const pathList = import.meta.glob('../../../../../../assets/images/chart/decorates/*') |
308 | 303 | return Object.keys(pathList) |
309 | 304 | .map(item => { |
310 | 305 | const imgName = item.split('/').at(-1) as string |
311 | - if (needBorder.includes(imgName)) { | |
312 | - return { | |
313 | - label: imgName, | |
314 | - value: imgName | |
315 | - } as SelectOption | |
316 | - } | |
306 | + if (!needBorder.includes(imgName)) return | |
307 | + return { | |
308 | + label: imgName, | |
309 | + value: imgName | |
310 | + } as SelectOption | |
317 | 311 | }) |
318 | 312 | .filter(Boolean) as SelectOption[] |
319 | 313 | }) |
320 | 314 | // |
321 | 315 | |
322 | -const getMapBorderImagePath = (name: string) => { | |
323 | - return isHref(name) ? name : new URL(`../../../../../../assets/images/chart/decorates/${name}`, import.meta.url).href | |
324 | -} | |
316 | +const getMapBorderImagePath = (name: string) => getImagePath('../../../../../../assets/images/chart/decorates', name) | |
325 | 317 | |
326 | -const renderMapBorderOption = (option: SelectOption) => { | |
327 | - return h(NSpace, { justify: 'space-between', style: 'padding: 0 15px; height: 28px; line-height: 28px;' }, () => [ | |
328 | - h(NImage, { | |
329 | - width: 25, | |
330 | - src: getMapBorderImagePath(option.value as string), | |
331 | - previewDisabled: true, | |
332 | - style: { height: '25px' } | |
333 | - } as Recordable), | |
334 | - h(NEllipsis, null, () => option.label) | |
335 | - ]) | |
336 | -} | |
318 | +const renderMapBorderOption = (option: SelectOption) => | |
319 | + renderCommonOption(option, getMapBorderImagePath(option.value as string)) | |
337 | 320 | |
338 | 321 | const selectMapBorderHandle = (value: string) => { |
339 | 322 | mapSelectBorderValue.value = value |
340 | 323 | const toLowerValue = value.toLocaleLowerCase() |
341 | 324 | ;(props.optionData.mapOptions.mpBorderConfig as BaseSelectBorderIF) = { |
342 | - value: toLowerValue[0]?.toUpperCase() + toLowerValue?.substr(1)?.split('.')[0] | |
343 | - } | |
325 | + value: toLowerValue[0]?.toUpperCase() + toLowerValue?.substring(1)?.split('.')[0] | |
326 | + } //这里首字母转大写,动态引入时匹配对应目录也是大写字母开头,即components\Decorates\Borders\Border01 | |
344 | 327 | } |
328 | +/** */ | |
329 | + | |
330 | +onMounted(() => { | |
331 | + iconMarkerValue.value = props.optionData.mapOptions.iconMarker?.split('/')?.at(-1) as string | |
332 | + props.optionData.mapOptions.iconMarker = getMarkerImagePath(iconMarkerValue.value) | |
333 | + mapSelectBorderValue.value = `${props.optionData.mapOptions.mpBorderConfig.value?.toLocaleLowerCase()}.png` | |
334 | +}) | |
345 | 335 | </script> | ... | ... |
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/1.png
renamed from
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position1.png
1.24 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/2.png
renamed from
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position2.png
1.4 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/3.png
renamed from
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position3.png
904 Bytes
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/4.png
renamed from
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position4.png
1.02 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/5.png
renamed from
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position5.png
970 Bytes
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position10.png
deleted
100644 → 0
1.2 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position11.png
deleted
100644 → 0
1.12 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position12.png
deleted
100644 → 0
1.93 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position13.png
deleted
100644 → 0
1.43 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position6.png
deleted
100644 → 0
1.51 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position7.png
deleted
100644 → 0
1.3 KB
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position8.png
deleted
100644 → 0
897 Bytes
src/packages/components/external/Charts/Maps/OverrideMapAmap/images/marker/position9.png
deleted
100644 → 0
1.61 KB
1 | 1 | <template> |
2 | 2 | <div @mouseenter="handleMouseenter" @mouseleave="handleMouseleave" class="chart-amap" ref="vChartRef"> |
3 | - <div v-show="showSearchBox" @click.stop="handleOpenSearchBox" class="search-box"></div> | |
4 | - <search-box :modelShow="modelShow" @searchParams="handleSearchParams" @closeDrawer="handleCloseDrawer"></search-box> | |
3 | + <!-- <div v-show="showSearchBox" @click.stop="handleOpenSearchBox" class="search-box"></div> | |
4 | + <search-box :modelShow="modelShow" @searchParams="handleSearchParams" @closeDrawer="handleCloseDrawer"></search-box> --> | |
5 | 5 | </div> |
6 | 6 | </template> |
7 | 7 | |
... | ... | @@ -16,7 +16,7 @@ import { isArray } from '@/utils' |
16 | 16 | import djh from './images/djh.png' |
17 | 17 | import online from './images/online.png' |
18 | 18 | import lx1 from './images/lx1.png' |
19 | -import positionImg from './images/marker/position1.png' | |
19 | +import onLineImg from './images/marker/3.png' | |
20 | 20 | import { getDeviceActiveTime, getDeviceList } from '@/api/external/common/index' |
21 | 21 | import dayjs from 'dayjs' |
22 | 22 | import SearchBox from './components/SearchBox.vue' |
... | ... | @@ -32,7 +32,7 @@ const modelShow = ref(false) |
32 | 32 | |
33 | 33 | const showSearchBox = ref(false) |
34 | 34 | |
35 | -let { | |
35 | +const { | |
36 | 36 | amapKey, |
37 | 37 | amapStyleKey, |
38 | 38 | amapLon, |
... | ... | @@ -46,8 +46,9 @@ let { |
46 | 46 | pitch, |
47 | 47 | skyColor, |
48 | 48 | marker, |
49 | - typeMarker, | |
50 | - mpBorderConfig | |
49 | + iconMarker, | |
50 | + mpBorderConfig, | |
51 | + bgColor | |
51 | 52 | } = toRefs(props.chartConfig.option.mapOptions) |
52 | 53 | |
53 | 54 | //官方没有高德地图api的ts,所以类型全用的any |
... | ... | @@ -104,7 +105,7 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => { |
104 | 105 | const res = await getDeviceActiveTime(tbDeviceId) //查询设备最后离线时间 |
105 | 106 | let { lastUpdateTs } = res[0] |
106 | 107 | const lastUpdateFormatTs = dayjs(lastUpdateTs).format('YYYY-MM-DD HH:mm:ss') |
107 | - //render方式渲染小组件里的边框组件 | |
108 | + //以render方式渲染小组件里的边框组件 | |
108 | 109 | const BorderInstance = await import(`../../../../Decorates/Borders/${mpBorderConfig.value.value}/index.vue`) |
109 | 110 | const config = await import(`../../../../Decorates/Borders/${mpBorderConfig.value.value}/config.ts`) |
110 | 111 | const BorderConfigInstance = new config.default() |
... | ... | @@ -132,7 +133,7 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => { |
132 | 133 | </div> |
133 | 134 | <div style="color:white;">所属组织:${organizationDTO.name}</div> |
134 | 135 | <div style="margin-top:6px;color:white">接入协议:${deviceProfile.transportType}</div> |
135 | - <div style="margin-top:6px;color:white"> | |
136 | + <div style="margin-top:6px;color:white;width:15vw;text-overflow: ellipsis;overflow: hidden; word-break: break-all;white-space: nowrap;"> | |
136 | 137 | 设备位置:${!deviceInfo.address ? '该设备暂无地理位置' : deviceInfo.address} |
137 | 138 | </div> |
138 | 139 | <div style="margin-top:6px;color:white"> |
... | ... | @@ -158,10 +159,15 @@ const handleCloseDrawer = () => (modelShow.value = false) |
158 | 159 | |
159 | 160 | const handleSearchParams = async (searchPage: any, params: any) => { |
160 | 161 | try { |
162 | + Object.keys(params).forEach(item => { | |
163 | + if (!params[item]) Reflect.deleteProperty(params, item) | |
164 | + }) | |
161 | 165 | const { items } = await getDeviceList(searchPage, params) |
162 | 166 | const values = filterDevice(items) |
163 | 167 | if (!values) return |
164 | - dataHandle(values) | |
168 | + setTimeout(() => { | |
169 | + dataHandle(values) | |
170 | + }, 1000) | |
165 | 171 | } finally { |
166 | 172 | handleCloseDrawer() |
167 | 173 | } |
... | ... | @@ -198,10 +204,11 @@ const dataHandle = (newData: dataJsonType) => { |
198 | 204 | // 记录新标记 |
199 | 205 | if (mapMarkerType.value === MarkerEnum.MARKER) { |
200 | 206 | newData.markers.forEach((markerItem: dataJsonMarkersType) => { |
207 | + const { deviceState } = markerItem.extraInfo | |
201 | 208 | const markerInstance = new AMapIns.Marker({ |
202 | 209 | position: [markerItem.position[0], markerItem.position[1]], |
203 | 210 | offset: new AMapIns.Pixel(-13, -30), |
204 | - icon: typeMarker.value || positionImg | |
211 | + icon: deviceState === 'ONLINE' ? onLineImg : iconMarker.value | |
205 | 212 | }) |
206 | 213 | // markers.push(markerInstance) 原作者这种方式添加,属于JS API 1.4.8版本的 |
207 | 214 | // markerInstance.setMap(mapIns) |
... | ... | @@ -255,7 +262,9 @@ watch( |
255 | 262 | // 预览 |
256 | 263 | useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => { |
257 | 264 | stopWatch() |
258 | - dataHandle(newData) | |
265 | + setTimeout(() => { | |
266 | + dataHandle(newData) | |
267 | + }, 1000) | |
259 | 268 | }) |
260 | 269 | </script> |
261 | 270 | |
... | ... | @@ -271,15 +280,9 @@ useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => { |
271 | 280 | } |
272 | 281 | .amap-info-content .go-border-box { |
273 | 282 | position: absolute; |
274 | - transform: scale(0.7); | |
283 | + transform: scale(0.68); | |
275 | 284 | top: -10px; |
276 | - /* opacity: 0,8; */ | |
277 | - /* background-color: rgba(0, 0, 0, 0.1); */ | |
278 | - background-color:rgba(255,255,255,0.1) | |
279 | -} | |
280 | -.amap-info-content .go-border-box svg { | |
281 | - /* background-color: rgba(0, 0, 0, 0.1); */ | |
282 | - /* background-color: rgba(255, 255, 255, 0.8); */ | |
285 | + background-color: v-bind(bgColor); | |
283 | 286 | } |
284 | 287 | </style> |
285 | 288 | <style lang="scss" scoped> | ... | ... |
... | ... | @@ -5,7 +5,7 @@ import cloneDeep from 'lodash/cloneDeep' |
5 | 5 | import { chartInitConfig } from '@/settings/designSetting' |
6 | 6 | |
7 | 7 | export const option = { |
8 | - dataset: [new URL('/src/assets/external/three/test.obj', import.meta.url).href],//三维数据源 | |
8 | + dataset: [new URL('/src/assets/external/three/test.obj', import.meta.url).href], //三维数据源 | |
9 | 9 | backgroundColor: '', //场景背景色 |
10 | 10 | backgroundAlpha: 0, //场景透明度 |
11 | 11 | enableDamping: false, //是否启用阻尼 |
... | ... | @@ -18,7 +18,9 @@ export const option = { |
18 | 18 | */ |
19 | 19 | outputEncoding: 'liner', |
20 | 20 | clearScene: false, //是否清空场景内容 |
21 | - lights: [//灯光为数组,type 为 环境光(AmbientLight) | 方向光(DirectionalLight) | 点光(PointLight) | 半球光(HemisphereLight) | |
21 | + lightInput: 1, | |
22 | + lights: [ | |
23 | + //灯光为数组,type 为 环境光(AmbientLight) | 方向光(DirectionalLight) | 点光(PointLight) | 半球光(HemisphereLight) | |
22 | 24 | { |
23 | 25 | type: 'AmbientLight', |
24 | 26 | label: '环境光(只有颜色)', |
... | ... | @@ -54,38 +56,41 @@ export const option = { |
54 | 56 | size: 1, |
55 | 57 | show: false |
56 | 58 | }, |
57 | - position: [//模型位置 | |
59 | + position: [ | |
60 | + //模型位置 | |
58 | 61 | { |
59 | 62 | x: 0, |
60 | 63 | y: 0, |
61 | 64 | z: 0 |
62 | 65 | } |
63 | 66 | ], |
64 | - rotation: [//模型旋转 | |
67 | + rotation: [ | |
68 | + //模型旋转 | |
65 | 69 | { |
66 | 70 | x: 0, |
67 | 71 | y: 0, |
68 | 72 | z: 0 |
69 | 73 | } |
70 | 74 | ], |
71 | - showFps:false,//是否显示fps | |
72 | - labels:[ //添加图片/文字标签,暂且支持文字 | |
75 | + showFps: false, //是否显示fps | |
76 | + labels: [ | |
77 | + //添加图片/文字标签,暂且支持文字 | |
73 | 78 | { |
74 | - image: "", | |
75 | - text: "", | |
79 | + image: '', | |
80 | + text: '', | |
76 | 81 | textStyle: { |
77 | - fontFamily: "Arial", | |
82 | + fontFamily: 'Arial', | |
78 | 83 | fontSize: 18, |
79 | - fontWeight: "normal", | |
84 | + fontWeight: 'normal', | |
80 | 85 | lineHeight: 1, |
81 | - color: "#ffffff", | |
86 | + color: '#ffffff', | |
82 | 87 | borderWidth: 8, |
83 | 88 | borderRadius: 4, |
84 | - borderColor: "rgba(0,0,0,1)", | |
85 | - backgroundColor: "rgba(0, 0, 0, 1)" | |
89 | + borderColor: 'rgba(0,0,0,1)', | |
90 | + backgroundColor: 'rgba(0, 0, 0, 1)' | |
86 | 91 | }, |
87 | - position: {x:0, y:0, z:0}, | |
88 | - scale:{x:1, y:1, z:0}, | |
92 | + position: { x: 0, y: 0, z: 0 }, | |
93 | + scale: { x: 1, y: 1, z: 0 }, | |
89 | 94 | sid: null |
90 | 95 | } |
91 | 96 | ] | ... | ... |
... | ... | @@ -11,15 +11,15 @@ |
11 | 11 | <n-input-number :min="0" v-model:value="optionData.borderConfig.size" size="small" /> |
12 | 12 | </setting-item> |
13 | 13 | </setting-item-box> |
14 | - <setting-item-box name="上传文件"> | |
14 | + <setting-item-box name="上传文件"> | |
15 | 15 | <setting-item> |
16 | 16 | <FileUpload |
17 | - :max="100" | |
18 | - :fileList="optionData.dataset" | |
19 | - :threeSupportFileFormat="threeSupportFileFormat" | |
20 | - :singleFileType="singleFileTypeNotMtl" | |
21 | - @fileStaticUri="handleFileStaticUri" | |
22 | - /> | |
17 | + :max="100" | |
18 | + :fileList="optionData.dataset" | |
19 | + :threeSupportFileFormat="threeSupportFileFormat" | |
20 | + :singleFileType="singleFileTypeNotMtl" | |
21 | + @fileStaticUri="handleFileStaticUri" | |
22 | + /> | |
23 | 23 | </setting-item> |
24 | 24 | </setting-item-box> |
25 | 25 | <setting-item-box :alone="true"> |
... | ... | @@ -78,8 +78,13 @@ |
78 | 78 | </template> |
79 | 79 | </setting-item> |
80 | 80 | </setting-item-box> |
81 | + <setting-item-box name="灯光选择"> | |
82 | + <setting-item name="灯光选择((0,环境光),(1,方向光),(2,点光),(3,半球光))"> | |
83 | + <n-input-number :min="0" :max="3" v-model:value="optionData.lightInput" size="small" /> | |
84 | + </setting-item> | |
85 | + </setting-item-box> | |
81 | 86 | <setting-item-box name="灯光配置"> |
82 | - <setting-item v-for="(item, index) in optionData.lights" :name="item.label" :key="index"> | |
87 | + <setting-item v-for="(item, index) in [optionData.lights[optionData.lightInput]]" :name="item.label" :key="index"> | |
83 | 88 | <n-color-picker |
84 | 89 | v-if="!includeHemisphereLight.includes(item.type)" |
85 | 90 | size="small" |
... | ... | @@ -180,15 +185,9 @@ |
180 | 185 | <SettingItem v-if="optionData.enableDamping" name="阻尼值"> |
181 | 186 | <n-input-number v-model:value="optionData.dampingFactor" :min="0" :max="1" size="small"></n-input-number> |
182 | 187 | </SettingItem> |
183 | - <SettingItem name="启用动画"> | |
184 | - <n-switch v-model:value="optionData.autoPlay" size="small" /> | |
185 | - </SettingItem> | |
186 | - <SettingItem name="输出编码"> | |
188 | + <SettingItem name="输出编码,可取值为 liner 或 sRGB。linear 是 LinearEncoding 线性编码, sRGB 即 sRGBEncoding rgb 模式编码(sRGBEncoding 能更好的还原材质颜色)"> | |
187 | 189 | <n-select v-model:value="optionData.outputEncoding" size="small" :options="encodinghList"></n-select> |
188 | 190 | </SettingItem> |
189 | - <SettingItem name="是否清空场景"> | |
190 | - <n-switch @change="handleChange" v-model:value="optionData.clearScene" size="small" /> | |
191 | - </SettingItem> | |
192 | 191 | </setting-item-box> |
193 | 192 | </collapse-item> |
194 | 193 | </template> |
... | ... | @@ -253,10 +252,6 @@ const encodinghList = [ |
253 | 252 | { label: 'sRGB ', value: 'sRGB ' } |
254 | 253 | ] |
255 | 254 | |
256 | -const handleChange = (e: boolean) => { | |
257 | - if (e) props.optionData.dataset = [''] | |
258 | -} | |
259 | - | |
260 | 255 | const handleFileStaticUri = (value: UploadFileInfo[]) => { |
261 | 256 | props.optionData.dataset = value.map(item => item?.url)?.filter(Boolean) as any |
262 | 257 | if (Array.isArray(props.optionData.dataset) && props.optionData.dataset.length === 0) { | ... | ... |
1 | 1 | <template> |
2 | - <div class="go-content-box" :style="{ border: !borderConfig.show ? 'none' : ''}"> | |
3 | - <div v-if="useDetectWebGLContext()"> | |
2 | + <div class="go-content-box" :style="{ border: !borderConfig.show ? 'none' : '' }"> | |
3 | + <div> | |
4 | 4 | <vue3dLoader |
5 | 5 | ref="vue3dLoaderRef" |
6 | 6 | :webGLRendererOptions="webGLRendererOptions" |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | @load="onLoad" |
21 | 21 | :position="position" |
22 | 22 | :rotation="rotation" |
23 | - :lights="lights" | |
23 | + :lights="[lights[lightInput]]" | |
24 | 24 | :showFps="showFps" |
25 | 25 | :labels="labels" |
26 | 26 | /> |
... | ... | @@ -29,15 +29,13 @@ |
29 | 29 | <n-progress type="line" :color="themeColor" :percentage="process" :indicator-placement="'inside'" processing /> |
30 | 30 | </div> |
31 | 31 | </div> |
32 | - <div v-else>您的浏览器不支持WebGL!</div> | |
33 | 32 | </div> |
34 | 33 | </template> |
35 | 34 | <script setup lang="ts"> |
36 | -import { PropType, toRefs, ref, nextTick, computed, watch } from 'vue' | |
35 | +import { PropType, toRefs, ref, nextTick, computed } from 'vue' | |
37 | 36 | import { CreateComponentType } from '@/packages/index.d' |
38 | 37 | import { vue3dLoader } from 'vue-3d-loader' |
39 | 38 | import { useDesignStore } from '@/store/modules/designStore/designStore' |
40 | -import { useDetectWebGLContext } from '@/utils/external/useSupportWebGL' | |
41 | 39 | |
42 | 40 | const designStore = useDesignStore() |
43 | 41 | |
... | ... | @@ -54,7 +52,6 @@ const themeColor = computed(() => { |
54 | 52 | |
55 | 53 | const vue3dLoaderRef = ref(null) |
56 | 54 | |
57 | -//threejs配置 | |
58 | 55 | const webGLRendererOptions = { |
59 | 56 | alpha: true, // 透明 |
60 | 57 | antialias: true, // 抗锯齿 |
... | ... | @@ -96,13 +93,9 @@ const { |
96 | 93 | rotation, |
97 | 94 | lights, |
98 | 95 | showFps, |
99 | - labels | |
100 | -} = toRefs(props.chartConfig.option) as any | |
101 | - | |
102 | -watch(dataset, (newData: string) => { | |
103 | - //dateset为空则清除场景 | |
104 | - if(!newData) clearScene.value=true | |
105 | -}) | |
96 | + labels, | |
97 | + lightInput | |
98 | +} = toRefs(props.chartConfig.option) as any | |
106 | 99 | </script> |
107 | 100 | |
108 | 101 | <style lang="scss" scoped> | ... | ... |
1 | 1 | <template> |
2 | 2 | <div> |
3 | 3 | <n-tree |
4 | + ref="nTreeRef" | |
4 | 5 | :accordion="treeConfig.accordion" |
5 | 6 | :checkable="treeConfig.checkable" |
6 | 7 | :default-expand-all="treeConfig.defaultExpandAll" |
... | ... | @@ -11,17 +12,20 @@ |
11 | 12 | label-field="name" |
12 | 13 | children-field="children" |
13 | 14 | @update:selected-keys="onClick" |
15 | + @update:checked-keys="onClick" | |
16 | + :checked-keys="checkedKeys" | |
14 | 17 | /> |
15 | 18 | </div> |
16 | 19 | </template> |
17 | 20 | |
18 | 21 | <script setup lang="ts"> |
19 | -import { PropType, toRefs } from 'vue' | |
22 | +import { PropType, toRefs, ref } from 'vue' | |
20 | 23 | import { CreateComponentType } from '@/packages/index.d' |
21 | 24 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
22 | 25 | import { useChartInteract } from '@/hooks/external/useChartSelectInteract.hook' |
23 | 26 | import { InteractEventOn } from '@/enums/eventEnum' |
24 | 27 | import { ComponentInteractParamsEnum } from './interact' |
28 | +import { NTree } from 'naive-ui' | |
25 | 29 | |
26 | 30 | const props = defineProps({ |
27 | 31 | chartConfig: { |
... | ... | @@ -32,7 +36,16 @@ const props = defineProps({ |
32 | 36 | |
33 | 37 | const { dataset, treeConfig } = toRefs(props.chartConfig.option) |
34 | 38 | |
39 | +const nTreeRef = ref<null | InstanceType<typeof NTree>>(null) | |
40 | + | |
41 | +const checkedKeys = ref([]) | |
42 | + | |
35 | 43 | const onClick = (v: string[]) => { |
44 | + // nTreeRef.value?.selectedKeys(v) | |
45 | + console.log(nTreeRef.value) | |
46 | + console.log(v) | |
47 | + // nTreeRef.value?.onUpdateCheckedKeys(v) | |
48 | + if (Array.isArray(v) && v.length == 0) return | |
36 | 49 | useChartInteract( |
37 | 50 | props.chartConfig, |
38 | 51 | useChartEditStore, | ... | ... |