From 1b0475068a27cb1742a4a3971dd6c08e77f006b6 Mon Sep 17 00:00:00 2001 From: Cano1997 <1978141412@qq.com> Date: Wed, 13 Aug 2025 21:29:26 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=9C=B0=E5=9B=BE=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=B8=8B=E9=92=BB=E3=80=81=E8=BF=94=E5=9B=9E=E3=80=81?= =?UTF-8?q?=E9=A1=B9=E6=A0=B7=E5=BC=8F=E3=80=81=E8=A1=8C=E6=94=BF=E7=AD=89?= =?UTF-8?q?=E7=BA=A7=E3=80=81=E6=BF=80=E6=B4=BB=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/map-chart-user/map-chart-user.scss | 9 +- src/common/map-chart-user/map-chart-user.tsx | 170 ++++++++++++++---- .../map-chart-user/map-chart-user.util.ts | 66 ++++++- src/common/map-chart-user/map-user-manager.ts | 80 +++++++-- 4 files changed, 272 insertions(+), 53 deletions(-) diff --git a/src/common/map-chart-user/map-chart-user.scss b/src/common/map-chart-user/map-chart-user.scss index 04a3d4108..f99339e0b 100644 --- a/src/common/map-chart-user/map-chart-user.scss +++ b/src/common/map-chart-user/map-chart-user.scss @@ -21,7 +21,14 @@ cursor: pointer; } + @include e(fullscreen) { + position: absolute; + top: getCssVar(spacing, tight); + right: getCssVar(spacing, tight); + z-index: 9; + } + @include e(popper) { - padding: getCssVar(spacing, base); + padding: getCssVar(spacing, tight); } } \ No newline at end of file diff --git a/src/common/map-chart-user/map-chart-user.tsx b/src/common/map-chart-user/map-chart-user.tsx index 4145a5751..1296c1e40 100644 --- a/src/common/map-chart-user/map-chart-user.tsx +++ b/src/common/map-chart-user/map-chart-user.tsx @@ -1,8 +1,17 @@ /* eslint-disable eqeqeq */ -import { defineComponent, onMounted, PropType, computed } from 'vue'; +import { + defineComponent, + onMounted, + PropType, + computed, + ref, + onBeforeUnmount, +} from 'vue'; import { isNil, mergeDeepLeft, mergeDeepWithKey } from 'ramda'; import { useNamespace } from '@ibiz-template/vue3-util'; import { IMapData, MapController } from '@ibiz-template/runtime'; +import { listenJSEvent, NOOP } from '@ibiz-template/core'; +import { toNumber } from 'lodash-es'; import { defaultOpts, getAreaOption, @@ -38,6 +47,8 @@ export const IBizMapChartUser = defineComponent({ const ns = useNamespace('map-chart-user'); const c = props.controller; let option: IData = defaultOpts; + const mapRef = ref(); + const isFull = ref(false); if (c.controlParams.defaultopts) { const data = JSON.parse(c.controlParams.defaultopts); option = mergeDeepLeft(data, option); @@ -53,57 +64,148 @@ export const IBizMapChartUser = defineComponent({ ); }); - const { chartRef, historyNames, changeMap, getCityInfo, goBack } = - useMapManager(props.controller, options, mapName => { - const areaData = props.areaData || []; - const pointData = props.pointData || []; + let cleanup = NOOP; - const tooltip = getTooltip(); - const visualMap = getVisualMap(options.value); - const cityInfo = getCityInfo(); - const pointOption = { - ...getPointStaticOption(options.value), - ...getPointOption(pointData, areaData), - }; - const areaOption = { - ...getAreaStaticOption(options.value), - ...getAreaOption(mapName, pointData, areaData, cityInfo), - }; + const { + chartRef, + historyNames, + processing, + areaLevelMap, + changeMap, + getCityInfo, + goBack, + } = useMapManager(props.controller, options, mapName => { + const areaData = props.areaData || []; + const pointData = props.pointData || []; - const result: IData = { - geo: { - map: mapName, - }, - tooltip, - visualMap, - series: [ - // 地图区块序列 - areaOption, - // 地图散点序列 - pointOption, - ], - }; - return result; - }); + const tooltip = getTooltip(); + const visualMap = getVisualMap(options.value); + const cityInfo = getCityInfo(); + const pointOption = { + ...getPointStaticOption(options.value), + ...getPointOption(pointData, areaData), + }; + const { top, bottom } = options.value; + const areaOption = { + top, + bottom, + ...getAreaStaticOption(options.value), + ...getAreaOption(mapName, pointData, areaData, cityInfo), + }; + + const result: IData = { + geo: { + map: mapName, + top, + bottom, + }, + tooltip, + visualMap, + series: [ + // 地图区块序列 + areaOption, + // 地图散点序列 + pointOption, + ], + }; + return result; + }); onMounted(() => { const name = options.value.defaultAreaCode; const areaCode = c.state.strAreaCode ? `${name}` : Number(name); c.state.areaCode = areaCode; changeMap(name, areaCode, true); + + c.evt.on('onDrillDown', async (args: IData) => { + if (!processing.value) { + const { data } = args; + const code = data.areaCode; + const curAreaCode = c.state.strAreaCode ? `${code}` : Number(code); + const areaLevel = areaLevelMap.get(toNumber(curAreaCode)) || ''; + c.state.areaCode = curAreaCode; + c.state.areaLevel = areaLevel; + await changeMap(code, code); + } + }); + c.evt.on('onBackClick', () => { + if (!processing.value) { + goBack(); + } + }); + + cleanup = listenJSEvent(window, 'resize', () => { + if (isFull.value) { + isFull.value = ibiz.fullscreenUtil.isFullScreen; + } + }); + }); + + // 组件销毁前销毁监听 + onBeforeUnmount(() => { + if (cleanup !== NOOP) { + cleanup(); + } }); - return { ns, chartRef, historyNames, goBack }; + const onBack = async () => { + processing.value = true; + await c.evt.emit('onBackClick', undefined); + goBack(); + processing.value = false; + }; + + /** + * @description 切换全屏 + */ + const toggleFullScreen = () => { + if (mapRef.value) { + if (isFull.value) { + ibiz.fullscreenUtil.closeElementFullscreen(); + } else { + ibiz.fullscreenUtil.openElementFullscreen(mapRef.value); + } + isFull.value = !isFull.value; + } + }; + + return { + ns, + c, + mapRef, + chartRef, + historyNames, + isFull, + onBack, + toggleFullScreen, + }; }, render() { + const { enabledFullScreen } = this.c.state; return ( -
+
+ {enabledFullScreen ? ( + + + + ) : null}
{this.historyNames.length > 1 && (
{ - this.goBack(); + this.onBack(); }} > {ibiz.i18n.t('app.return')} diff --git a/src/common/map-chart-user/map-chart-user.util.ts b/src/common/map-chart-user/map-chart-user.util.ts index becc662ba..33eef61ce 100644 --- a/src/common/map-chart-user/map-chart-user.util.ts +++ b/src/common/map-chart-user/map-chart-user.util.ts @@ -43,10 +43,39 @@ export const defaultOpts = { jsonBaseUrl: `${ibiz.env.assetsUrl}/json/map`, /** 默认打开的区域编码 */ defaultAreaCode: 100000 as string | number, + // 距离底部距离 + bottom: 20, + // 距离顶部距离 + top: 20, }; export type MapOptions = typeof defaultOpts; +/** + * @description 获取项样式 + * @param {IData} item + * @returns {*} {string} + */ +const getItemStyle = (item: IData): string => { + const itemStyle = []; + if (item._color) { + itemStyle.push(`color:${item._color}`); + } + if (item._bgcolor) { + itemStyle.push(`background:${item._bgcolor}`); + } + if (item._borderColor) { + itemStyle.push(`border-color:${item._borderColor}`); + } + if (item._borderWidth) { + itemStyle.push(`border-width:${item._borderWidth}px`); + } + if (item._borderWidth && item._borderColor) { + itemStyle.push(`border-style:solid`); + } + return itemStyle.join(';'); +}; + export const findData = ( id: string, type: 'area' | 'point', @@ -119,9 +148,21 @@ export const getPointOption = ( return; } const find = findData(params.data._id, 'point', pointData, areaData)!; - return `
${find?._tooltip}
`; + if (!find) { + return; + } + const { _deData: data } = find; + let text = data.srfmajortext; + if (find._value) { + text = `${data.srfmajortext}: ${find._value}`; + } + if (find._tooltip) { + text = find._tooltip; + } + const style = getItemStyle(find); + return `
${text}
`; }, padding: 0, }; @@ -189,9 +230,22 @@ export const getAreaOption = ( return; } const find = findData(params.data._id, 'area', pointData, areaData)!; - return `
${find?._tooltip}
`; + if (!find || (!find._tooltip && !find._value)) { + return; + } + const { _deData: data } = find; + let text = data.srfmajortext; + if (find._value) { + text = `${data.srfmajortext}: ${find._value}`; + } + if (find._tooltip) { + text = find._tooltip; + } + // 项样式作为弹框样式,弹框默认内容为主信息+值,可配置提示属性实体处理逻辑来调整提示框内容 + const style = getItemStyle(find); + return `
${text}
`; }, padding: 0, }; diff --git a/src/common/map-chart-user/map-user-manager.ts b/src/common/map-chart-user/map-user-manager.ts index 76cb9e17c..c9212a066 100644 --- a/src/common/map-chart-user/map-user-manager.ts +++ b/src/common/map-chart-user/map-user-manager.ts @@ -3,6 +3,7 @@ import { registerMap as register, EChartsType, init } from 'echarts'; import { ComputedRef, onMounted, onUnmounted, ref } from 'vue'; import { IMapData, MapController } from '@ibiz-template/runtime'; import { listenJSEvent } from '@ibiz-template/core'; +import { toNumber } from 'lodash-es'; import { findData, MapOptions, getJsonUrl } from './map-chart-user.util'; /** @@ -26,6 +27,10 @@ export function useMapManager( const historyNames = ref([]); + const areaLevelMap = new Map(); + + const processing = ref(false); + let chart: EChartsType; const chartRef = ref(); @@ -38,8 +43,9 @@ export function useMapManager( noChild: json.features.length === 1, }; json.features.forEach((item: IData) => { - const { adcode, name } = item.properties; + const { adcode, name, level } = item.properties; info.cityNames[adcode] = name; + areaLevelMap.set(adcode, level); }); return info; }; @@ -76,16 +82,19 @@ export function useMapManager( areaCode: string | number, isInit: boolean = false, ) => { - if (!isInit) { - controller.onMapChange(areaCode); - } const strName = `${name}`; - if (!mapInfos.has(strName)) { await registerMap(strName); } - controller.state.mapInfo = getCityInfo()!; + if (!isInit) { + controller.onMapChange(areaCode); + } else { + // 初次加载设置默认行政等级 + const areaLevel = areaLevelMap.get(toNumber(areaCode)) || ''; + controller.state.areaLevel = areaLevel; + } currentName.value = strName; + controller.state.mapInfo = getCityInfo()!; historyNames.value.push(strName); refresh(); }; @@ -96,8 +105,9 @@ export function useMapManager( historyNames.value.pop(); // 先删除当前地图的name const name = historyNames.value.pop(); // 获取上一个地图的name const areaCode = opts.value.strAreaCode ? `${name}` : Number(name); + const areaLevel = areaLevelMap.get(toNumber(areaCode)) || ''; controller.state.areaCode = areaCode; - await controller.evt.emit('onBackClick', undefined); + controller.state.areaLevel = areaLevel; changeMap(name!, areaCode); } }; @@ -118,36 +128,80 @@ export function useMapManager( resizeObserver.observe(chartRef.value); } chart.on('click', (params: IData) => { - // 散点点击事件 if (params.componentType === 'series') { + // 散点点击事件 if (params.seriesType === 'scatter') { if (!params.data) { return; } + processing.value = true; const { pointData, areaData } = controller.state; const data = findData(params.data._id, 'point', pointData, areaData); if (data) { controller.onPointClick(data as IMapData); } + processing.value = false; return; } + // 区域点击事件 if (params.seriesType === 'map') { + processing.value = true; const areaCode = opts.value.strAreaCode ? `${params.name}` : Number(params.name); - controller.state.areaCode = areaCode; - const { pointData, areaData, enabledDrillDown } = controller.state; + const areaLevel = areaLevelMap.get(toNumber(areaCode)) || ''; + const { pointData, areaData, enabledDrillDown, mdctrlActiveMode } = + controller.state; if (params.data) { const data = findData(params.data._id, 'area', pointData, areaData); if (data) { - controller.onAreaClick(data as IMapData); + controller.onAreaClick(data as IMapData, areaCode, areaLevel); } } // 禁止切换同一个地图,到最下级的时候会出现这种情况 - if (params.name !== currentName.value && enabledDrillDown) { + if ( + params.name !== currentName.value && + enabledDrillDown && + mdctrlActiveMode !== 2 + ) { + // 行政编码大于当前编码即下钻 + if (toNumber(areaCode) > toNumber(controller.state.areaCode)) { + controller.evt.emit('onDrillDown', { data: { areaCode } }); + } + controller.state.areaCode = areaCode; + controller.state.areaLevel = areaLevel || ''; changeMap(params.name, areaCode); } + processing.value = false; + } + } + }); + chart.on('dblclick', (params: IData) => { + // 区域点击事件 + const { enabledDrillDown, mdctrlActiveMode } = controller.state; + if ( + params.componentType === 'series' && + params.seriesType === 'map' && + mdctrlActiveMode === 2 && + enabledDrillDown + ) { + processing.value = true; + const areaCode = opts.value.strAreaCode + ? `${params.name}` + : Number(params.name); + const areaLevel = areaLevelMap.get(toNumber(areaCode)) || ''; + // 行政编码大于当前编码即下钻 + if (toNumber(areaCode) > toNumber(controller.state.areaCode)) { + controller.evt.emit('onDrillDown', { data: { areaCode } }); + } + controller.state.areaCode = areaCode; + controller.state.areaLevel = areaLevel; + + // 禁止切换同一个地图,到最下级的时候会出现这种情况 + if (params.name !== currentName.value) { + changeMap(params.name, areaCode); } + processing.value = false; } }); @@ -193,6 +247,8 @@ export function useMapManager( chartRef, historyNames, currentName, + processing, + areaLevelMap, changeMap, getCityInfo, goBack, -- Gitee From 3382a537bb917fc846edadf54a5ffce28e3d6c28 Mon Sep 17 00:00:00 2001 From: Cano1997 <1978141412@qq.com> Date: Wed, 13 Aug 2025 21:30:17 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=9C=B0=E5=9B=BE=E5=86=85?= =?UTF-8?q?=E7=BD=AE=E5=AF=BC=E8=88=AA=E5=8C=BA=E5=9F=9F=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A1=8C=E6=94=BF=E7=BC=96=E7=A0=81=E4=B8=8E?= =?UTF-8?q?=E8=A1=8C=E6=94=BF=E7=AD=89=E7=BA=A7=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ .../provider/map-navigation.provider.ts | 31 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1ad7e994..60773bcc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ - 新增甘特图滑块的链接线绘制,新增部件参数linkdatasourcetype(链接数据获取模式)、linkappdataentityname(链接数据集应用实体名称)、linkappdedatasetname(链接应用实体结果集名称)、linknodedataname(链接节点数据属性名称)、fromdataitemname(链接起始数据项属性名称)、todataitemname(链接结束数据项属性名称) - 新增树节点数据拖拽状态属性 - 异步导出下载识别文件名属性 +- 地图支持下钻、返回、项样式、行政等级、激活模式 +- 地图内置导航区域导航添加行政编码与行政等级参数 ### Changed diff --git a/src/common/control-navigation/provider/map-navigation.provider.ts b/src/common/control-navigation/provider/map-navigation.provider.ts index 2387a1c59..58319ba14 100644 --- a/src/common/control-navigation/provider/map-navigation.provider.ts +++ b/src/common/control-navigation/provider/map-navigation.provider.ts @@ -1,4 +1,9 @@ -import { IMapData, INavViewMsg, MapController } from '@ibiz-template/runtime'; +import { + IMapData, + IMapEvent, + INavViewMsg, + MapController, +} from '@ibiz-template/runtime'; import { ISysMap } from '@ibiz/model-core'; import { NavgationBaseProvider } from './navigation-base.provider'; @@ -16,6 +21,20 @@ export class MapNavigationProvider extends NavgationBaseProvider { declare model: ISysMap; + /** + * @description 导航数据变化 + * @param {IMapEvent['onNavDataChange']['event']} event + * @memberof MapNavigationProvider + */ + onNavDataChange(event: IMapEvent['onNavDataChange']['event']): void { + const { navData } = event; + // 数据变更才重新导航 + if (this.navViewMsg.value?.key !== navData._id) { + this.navStack.unshift(navData[this.keyName]); + this.navViewMsg.value = this.getNavViewMsg(navData as IMapData); + } + } + onNavDataByStack(): void { const { items } = this.controller.state; const navData = @@ -30,16 +49,22 @@ export class MapNavigationProvider extends NavgationBaseProvider { } } - getNavViewMsg(item: IMapData): INavViewMsg { + getNavViewMsg(item: IData): INavViewMsg { const { sysMapItems } = this.model; + const { areaCode, areaLevel } = item; const itemModel = sysMapItems?.find(_item => _item.id === item._mapItemId); if (itemModel) { const { context, params } = this.prepareParams( itemModel, - item._deData, + { ...item._deData, areaCode, areaLevel }, this.controller.context, this.controller.params, ); + // 区域导航视图添加行政编码与行政等级 + if (itemModel.itemStyle?.startsWith('REGION')) { + params.srfareacode = areaCode; + params.srfarealevel = areaLevel; + } return { params, context, -- Gitee