diff --git a/src/components/V2504/ChartWithLegend/index.less b/src/components/V2504/ChartWithLegend/index.less index 582c9288d3b98ed27d7646910a1e1a5c5b349c7a..2d714e1c15037b20a8af731e03f4d9da725f77f5 100644 --- a/src/components/V2504/ChartWithLegend/index.less +++ b/src/components/V2504/ChartWithLegend/index.less @@ -26,6 +26,10 @@ margin-left: -24px; margin-right: -10px; } +.chart-thin-short-legend{ + margin-left: -14px; + margin-right: -10px; +} .legend { flex: 1; @@ -62,6 +66,10 @@ margin-bottom: 0; } } +.shortLegendItem{ + width: 286px; + margin-left: 20px; +} .legendItemContent { display: flex; @@ -87,11 +95,15 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - max-width: 120px; + min-width: 120px; +} +.shortName{ + min-width: 80px; } .valueSection { display: flex; + // flex: 1; min-width: 103px; // margin-right: 10px; justify-content: flex-end; @@ -103,6 +115,10 @@ font-family: DIN; font-size: 20px; font-weight: 700; + margin-left: 14px; +} +.shortValue{ + margin-left: 2px; } .unit { @@ -111,6 +127,7 @@ font-size: 16px; font-weight: 400; line-height: 21px; + margin-left: 4px; margin-right: 8px; } diff --git a/src/components/V2504/ChartWithLegend/index.tsx b/src/components/V2504/ChartWithLegend/index.tsx index 33b69f1cdc106508b24109775c9663d8892c1366..7c691179442a3fc1232d30b64532aedc88dffa4e 100644 --- a/src/components/V2504/ChartWithLegend/index.tsx +++ b/src/components/V2504/ChartWithLegend/index.tsx @@ -27,6 +27,9 @@ export interface ChartWithLegendProps { legendHeight?: number; fullCountOfLegend?: number; showLabel?: boolean; + labelFormatter?: string; + labelFormatterParams?: {}; + isShortLegendItem?: boolean; } const ChartWithLegend: React.FC = ({ @@ -43,6 +46,26 @@ const ChartWithLegend: React.FC = ({ legendHeight = 120, fullCountOfLegend = 3, showLabel = false, + labelFormatter = [ + `{b|${15.21}}`,`{a|万辆}` + ].join('\n'), + labelFormatterParams = { + a: { + fontFamily: '微软雅黑', + fontSize: 16, + fontWeight: 400, + color: '#BCCEE9', + }, + b: { + fontFamily: 'D-DIN', + fontSize: 24, + fontWeight: 700, + color: '#FFFFFF', + lineHeight: 36, + // padding: [8, 8, 0, 0] + }, + }, + isShortLegendItem = false, }) => { const chartRef = useRef(null); @@ -59,14 +82,21 @@ const ChartWithLegend: React.FC = ({ // 自定义 tooltip 格式,确保文本和数值在同一行 const { name, value, percent } = params; const valueText = showCount ? value + unit : ''; - const percentText = showPercentage ? percent.toFixed(2) + '%' : ''; - console.log(params); + // const percentText = showPercentage ? percent.toFixed(2) + '%' : ''; + // console.log(params); // return `
// 可以分行展示,设置最大宽度并使用省略号 + // return `
+ // ${name}: ${valueText} + //
`; + // ${name}: ${valueText} ${percentText} + return `
- ${name}: ${valueText} ${percentText} + + ${name}: ${valueText}
`; + // return `${name}: ${valueText}`; // return `
//
${name}
@@ -93,26 +123,8 @@ const ChartWithLegend: React.FC = ({ }, ], label: { - formatter: [ - `{b|${15.21}}`, - `{a|万辆}` - ].join('\n'), - rich: { - a: { - fontFamily: '微软雅黑', - fontSize: 16, - fontWeight: 400, - color: '#BCCEE9', - }, - b: { - fontFamily: 'D-DIN', - fontSize: 24, - fontWeight: 700, - color: '#FFFFFF', - lineHeight: 36, - // padding: [8, 8, 0, 0] - }, - } + formatter: labelFormatter, + rich: labelFormatterParams, } }; @@ -125,7 +137,7 @@ const ChartWithLegend: React.FC = ({ {title &&
{title}
} -
+
= ({
{/*
*/} {data.map((item, index) => ( -
+
- {item.name} + {item.name}
{showCount && ( <> - + = ({ {showPercentage && ( <> - + acc + curr.value, 0)) * 100).toFixed(2))} separator="," diff --git a/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.less b/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.less index 1755a27a11123f54715cc9e405bf295146ac80db..d60452241c345c1146d46f428b6588fc0d8b1b7a 100644 --- a/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.less +++ b/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.less @@ -56,7 +56,8 @@ .subNavItems { position: absolute; - bottom: 81px; + bottom: 71px; // tsj: 这里高度要设置为71px,否则会导致鼠标上移进入与子菜单项的中间区域,导致子菜单项消失。 + // bottom: 81px; width: 505px; // tsj: 这里宽度要设置为505px,否则会导致子菜单项由于宽度不够展示不出来。 left: 0; // tsj: 这里left要设置为0,否则会导致整个菜单栏偏移。 diff --git a/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.tsx b/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.tsx index 586f19d83aee139491bae78ea3eae697304d34ec..2945c525385136014161365251015c0d60599a33 100644 --- a/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.tsx +++ b/src/pages/Home_v_2504/components/MapContainer/NavigationBar/index.tsx @@ -231,7 +231,10 @@ const NavigationBar: React.FC = () => { {hoveredKey === item.key && item.hasChildren && item.children && (
setHoveredKey(item.key)} // 确保子菜单悬停时父菜单仍保持激活 + onMouseEnter={() => { + //console.log('***** son onMouseEnter item', item) + setHoveredKey(item.key) + }} // 确保子菜单悬停时父菜单仍保持激活 > {item.children.map(subItem => (
{ return DATA_TYPE.ENVIRONMENT.SANITATION_ALERT; case '环卫设施': return DATA_TYPE.ENVIRONMENT.SANITATION_FACILITY; + case '市政设施': + return DATA_TYPE.MUNICIPAL.MUNICIPAL_EVENT; + case '景观照明': + return DATA_TYPE.LANDSCAPE_LIGHTING.LIGHTING_EVENT; + default: return DATA_TYPE.RESTAURANT_OIL.OIL_SMOKE_EVENT; } diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingGridDistribution/index.less b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingGridDistribution/index.less new file mode 100644 index 0000000000000000000000000000000000000000..765a3a78759b46b30c51a68513a8f399f00df8fa --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingGridDistribution/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 272px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 12px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingGridDistribution/index.tsx b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingGridDistribution/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3ab408fcf56faade7818d30f35f2f647798175d3 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingGridDistribution/index.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface LightingGridDistributionProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const LightingGridDistribution: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '景观照明', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(195, 139, 79)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: '监管东所监管东所监管东所监管东所', value: 456, percent: '52.2' }, + { name: '监管西所', value: 400, percent: '47.8' }, + { name: '监管南所', value: 322, percent: '30.0' }, + { name: '监管北所', value: 186, percent: '20.0' }, + { name: '监管中所', value: 152, percent: '10.0' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载景观照明-市管功能照明网格分布-数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default LightingGridDistribution; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingLampCount/index.less b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingLampCount/index.less new file mode 100644 index 0000000000000000000000000000000000000000..765a3a78759b46b30c51a68513a8f399f00df8fa --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingLampCount/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 272px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 12px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingLampCount/index.tsx b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingLampCount/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a35c66d73c55b1b2b342869ab2b6a2baa0119a3f --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/LightingLampCount/index.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface LightingLampCountProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const LightingLampCount: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '景观照明', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(195, 139, 79)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: 'LED光源灯盏数', value: 456, percent: '52.2' }, + // { name: '钠灯灯盏数', value: 400, percent: '47.8' }, + // { name: '金卤灯灯盏数', value: 322, percent: '30.0' }, + // { name: '高压钠灯灯盏数', value: 186, percent: '20.0' }, + { name: '其他灯盏数', value: 152, percent: '10.0' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载景观照明-市管功能照明灯盏数-数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default LightingLampCount; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationStatus/index.less b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationStatus/index.less new file mode 100644 index 0000000000000000000000000000000000000000..dab8b639d7fa97bacca2e22c708caa24ab20152d --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationStatus/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 272px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 0px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationStatus/index.tsx b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationStatus/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7a50fdfb59dcc4937a8aafebb9cf6700d212e873 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationStatus/index.tsx @@ -0,0 +1,169 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface OperationStatusProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const OperationStatus: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '景观照明', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: 'I等', value: 456, percent: '97.2' }, + { name: 'II等', value: 400, percent: '83.5' }, + { name: 'III等', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载景观照明-运行情况数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+
+
+ ); +}; + +export default OperationStatus; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationTrend/index.less b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationTrend/index.less new file mode 100644 index 0000000000000000000000000000000000000000..336673d935524309ea454206cf71256cf03c19e9 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationTrend/index.less @@ -0,0 +1,16 @@ +.container { + width: 530px; + height: 272px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + padding-bottom: 20px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + margin-top: 10px; + overflow: hidden; + } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationTrend/index.tsx b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationTrend/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3ef8be128b3ea4964dcdf5595e003caf1e179f83 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/OperationTrend/index.tsx @@ -0,0 +1,213 @@ +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import styles from './index.less'; +import HncyCard from '@/pages/Home_v_2504/components/common/Card' +import AreaBarList, { AreaBarItem } from '@/components/V2504/AreaBarList' +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs' +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import { getDistrictHighFrequencyArea } from '@/services/CityProblem'; +import { CarAreaProps } from '@/pages/Home_v_2504/components/SubPages/Environment/components/LeftContent/components/CarArea'; +import BridgeAreaDistribution, { BridgeAreaDistributionProps } from '@/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeAreaDistribution'; + +// 类型定义 +export interface OperationTrendProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; +} +const OperationTrend: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '景观照明' +}) => { + + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + + // 环卫人员区域数据 + // const [data, setData] = useState([]); + const [data, setData] = useState([ + { name: '锦江区', count: 1456, percentage: 97.2 }, + { name: '金牛区', count: 1400, percentage: 83.5 }, + { name: '成华区', count: 1322, percentage: 70.8 }, + { name: '青羊区', count: 1286, percentage: 65.6 }, + { name: '双流区', count: 1252, percentage: 12.9 }, + { name: '武侯区', count: 1122, percentage: 10.6 }, + { name: '龙泉驿区', count: 1121, percentage: 10.5 }, + { name: '温江区', count: 1120, percentage: 10.4 }, + { name: '新都区', count: 1119, percentage: 10.3 }, + { name: '郫都区', count: 1118, percentage: 10.2 }, + { name: '都江堰市', count: 1117, percentage: 10.1 } + ]); + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.leftPanelTime?.startTime || !currentMapState.leftPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.leftPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理环卫人员区域API调用 + const highFrequencyApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起环卫人员区域请求,参数:', params); + const response = await getDistrictHighFrequencyArea(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取环卫人员区域数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + setData([]); + return; + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseFloat(item.value) === 0 && parseFloat(item.percent) === 0)) { + // data = [ + // { name: '锦江区', value: 456, percent: '97.2' }, + // { name: '金牛区', value: 400, percent: '83.5' }, + // { name: '成华区', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + // { name: '武侯区', value: 122, percent: '10.6' }, + // { name: '龙泉驿区', value: 121, percent: '10.5' }, + // { name: '温江区', value: 120, percent: '10.4' }, + // { name: '新都区', value: 119, percent: '10.3' }, + // { name: '郫都区', value: 118, percent: '10.2' }, + // { name: '都江堰市', value: 117, percent: '10.1' } + // ]; + // console.log('使用模拟环卫人员区域数据'); + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name, + percentage: parseFloat(item.percent) || 0, + count: parseInt(item.value) || 0 + })); + + console.log('环卫人员区域数据成功:'); + setData(formattedData); + }, + onError: (error) => { + console.error('获取环卫人员区域数据出错:', error); + setData([]); + }, + apiName: '环卫人员区域', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 使用 useMemo 跟踪 rightPanelTime 的实际变化 + const memoizedRightPanelTime = useMemo(() => { + return { + type: mapState.rightPanelTime.type, + startTime: mapState.rightPanelTime.startTime, + endTime: mapState.rightPanelTime.endTime + }; + }, [ + mapState.rightPanelTime.type, + mapState.rightPanelTime.startTime, + mapState.rightPanelTime.endTime + ]); + + // 跟踪上一次的API参数,避免重复调用 + const prevApiParamsRef = useRef(''); + + // 在地图状态变化和Tab变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载环卫人员区域数据'); + return; + } + + // 参数签名,用于比较参数是否有实际变化 + const paramsSignature = JSON.stringify(params); + + // 检查参数是否真正变化,防止重复调用 + if (paramsSignature === prevApiParamsRef.current) { + console.log('环卫人员区域参数未变化,跳过重复加载'); + return; + } + + console.log('加载景观照明-近半年运行趋势数据,参数:', params); + // highFrequencyApi.callApi(params); + + // 更新上一次参数签名 + prevApiParamsRef.current = paramsSignature; + + }, [mapState.regionCode, memoizedRightPanelTime, buildApiParams, highFrequencyApi]); + + return ( +
+ +
+
+
+ ) +} + +export default OperationTrend; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/SensingDevice/index.less b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/SensingDevice/index.less new file mode 100644 index 0000000000000000000000000000000000000000..765a3a78759b46b30c51a68513a8f399f00df8fa --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/SensingDevice/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 272px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 12px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/SensingDevice/index.tsx b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/SensingDevice/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c0d815e9613ba6cd295229151f09dd58ac319d88 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/SensingDevice/index.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface SensingDeviceProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const SensingDevice: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '景观照明', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(195, 139, 79)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: '固定式照明灯盏数', value: 456, percent: '52.2' }, + { name: '中灯控制器', value: 400, percent: '47.8' }, + { name: '水浸监测', value: 322, percent: '30.0' }, + { name: '集中控制器', value: 186, percent: '20.0' }, + // { name: '其他', value: 152, percent: '10.0' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载景观照明-感知设备-数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default SensingDevice; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/YesterdayPowerTrend/index.less b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/YesterdayPowerTrend/index.less new file mode 100644 index 0000000000000000000000000000000000000000..90c6ad7b3e32985b1132239eb1c366c35ac46a5d --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/YesterdayPowerTrend/index.less @@ -0,0 +1,16 @@ +.container { + width: 530px; + height: 272px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + +.chartWrapper { + height: calc(100% - 52px); + padding: 10px 24px 23px 19px; +} \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/YesterdayPowerTrend/index.tsx b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/YesterdayPowerTrend/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fa78a3ce78e99214fa83c754d74c14fc2e924214 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/components/YesterdayPowerTrend/index.tsx @@ -0,0 +1,204 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; +import SmoothLineChart from '@/components/V2504/SmoothLineChart'; + +interface YesterdayPowerTrendProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +interface TrendData { + time: string; + value: number; +} + +const YesterdayPowerTrend: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '景观照明', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { time: '00:00:00', value: 145 }, + { time: '01:00:00', value: 160 }, + { time: '02:00:00', value: 155 }, + { time: '03:00:00', value: 165 }, + { time: '04:00:00', value: 175 }, + { time: '05:00:00', value: 185 }, + { time: '06:00:00', value: 180 }, + { time: '07:00:00', value: 190 }, + { time: '08:00:00', value: 195 }, + { time: '09:00:00', value: 205 }, + { time: '10:00:00', value: 210 }, + { time: '11:00:00', value: 215 }, + { time: '12:00:00', value: 220 }, + { time: '13:00:00', value: 210 }, + { time: '14:00:00', value: 205 }, + { time: '15:00:00', value: 195 }, + { time: '16:00:00', value: 200 }, + { time: '17:00:00', value: 205 }, + { time: '18:00:00', value: 210 }, + { time: '19:00:00', value: 215 }, + { time: '20:00:00', value: 225 }, + { time: '21:00:00', value: 230 }, + { time: '22:00:00', value: 235 }, + { time: '23:00:00', value: 240 }, + ]; + }else{ + setData([]); + return; + } + } + // console.log('使用模拟问题来源数据'); + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + // const formattedData = data.map((item: any) => ({ + // name: item.name || '未知来源', + // value: parseInt(item.value) || 0, + // percentage: parseFloat(item.percent) || 0 + // })); + + // console.log('问题来源数据成功:', formattedData); + setData(data); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载景观照明-昨日功率趋势数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default YesterdayPowerTrend; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/index.tsx b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/index.tsx index ca4179e4e04a8f57cb5766842757bc14400d5d68..dee263877d38bed93bdb8ed120ecd025f74eaeb1 100644 --- a/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/index.tsx +++ b/src/pages/Home_v_2504/components/SubPages/LandscapeLighting/components/LeftContent/index.tsx @@ -1,7 +1,12 @@ import React from 'react'; import styles from './index.less'; import PanelTitle from '@/pages/Home_v_2504/components/common/PanelTitle'; - +import LightingGridDistribution from './components/LightingGridDistribution'; +import OperationStatus from './components/OperationStatus'; +import YesterdayPowerTrend from './components/YesterdayPowerTrend'; +import OperationTrend from './components/OperationTrend'; +import LightingLampCount from './components/LightingLampCount'; +import SensingDevice from './components/SensingDevice'; /** * 景观照明左侧内容组件 */ @@ -11,15 +16,15 @@ const LeftContent: React.FC = () => { {/* 标题 */}
- {/* */} -
+
-

此处为景观照明监管左侧内容区域

+ + + + + +
); diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeAreaDistribution/index.less b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeAreaDistribution/index.less new file mode 100644 index 0000000000000000000000000000000000000000..38e9a1a0cc5109e3c29f46ae4b77c8583f14635e --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeAreaDistribution/index.less @@ -0,0 +1,16 @@ +.container { + width: 530px; + height: 311px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + padding-bottom: 20px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + margin-top: 10px; + overflow: hidden; + } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeAreaDistribution/index.tsx b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeAreaDistribution/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..09ef5d6d0b992161b4085d49ebd43aed1e5545be --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeAreaDistribution/index.tsx @@ -0,0 +1,273 @@ +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import styles from './index.less'; +import HncyCard from '@/pages/Home_v_2504/components/common/Card' +import AreaBarList, { AreaBarItem } from '@/components/V2504/AreaBarList' +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs' +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import { getDistrictHighFrequencyArea } from '@/services/CityProblem'; +import { CarAreaProps } from '@/pages/Home_v_2504/components/SubPages/Environment/components/LeftContent/components/CarArea'; + +// 类型定义 +export interface BridgeAreaDistributionProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; +} + +// 区域类型定义 +export type AreaType = 'all' | 'urban' | 'central' | 'county'; +const BridgeAreaDistribution: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市政设施' +}) => { + + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 当前选中的区域类型 + const [currentTab, setCurrentTab] = useState('all'); + const currentTabRef = useLatestValue(currentTab); + + // 环卫人员区域数据 + // const [data, setData] = useState([]); + const [data, setData] = useState([ + { name: '锦江区', count: 1456, percentage: 97.2 }, + { name: '金牛区', count: 1400, percentage: 83.5 }, + { name: '成华区', count: 1322, percentage: 70.8 }, + { name: '青羊区', count: 1286, percentage: 65.6 }, + { name: '双流区', count: 1252, percentage: 12.9 }, + { name: '武侯区', count: 1122, percentage: 10.6 }, + { name: '龙泉驿区', count: 1121, percentage: 10.5 }, + { name: '温江区', count: 1120, percentage: 10.4 }, + { name: '新都区', count: 1119, percentage: 10.3 }, + { name: '郫都区', count: 1118, percentage: 10.2 }, + { name: '都江堰市', count: 1117, percentage: 10.1 } + ]); + + // 处理Tab切换 + const handleTabChange = (tab: string) => { + setCurrentTab(tab as AreaType); + }; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 区域编码生成函数 + const getRegionCodes = (areaType: AreaType, regionCode: string) => { + // 默认所有区域 + if (areaType === 'all') { + return regionCode.length > 4 + ? regionCode + : regionCode === '5101' + ? '510104,510105,510106,510107,510108,510112,510113,510114,510115,510116,510117,510121,510129,510131,510132,510181,510182,510183,510184,510185' + : ''; + } + + // 城市新区 + if (areaType === 'urban') { + return '510112,510113,510114,510115,510116,510117'; + } + + // 中心城区 + if (areaType === 'central') { + return '510104,510105,510106,510107,510108'; + } + + // 县市新城 + if (areaType === 'county') { + return '510121,510129,510131,510132,510181,510182,510183,510184,510185'; + } + + return ''; + }; + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.leftPanelTime?.startTime || !currentMapState.leftPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.leftPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 获取区域编码列表 + const districtCodeList = getRegionCodes(currentTabRef.current, currentMapState.regionCode); + if (districtCodeList) { + params.districtCodeList = districtCodeList; + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, currentTabRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理环卫人员区域API调用 + const highFrequencyApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起环卫人员区域请求,参数:', params); + const response = await getDistrictHighFrequencyArea(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取环卫人员区域数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + setData([]); + return; + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseFloat(item.value) === 0 && parseFloat(item.percent) === 0)) { + // data = [ + // { name: '锦江区', value: 456, percent: '97.2' }, + // { name: '金牛区', value: 400, percent: '83.5' }, + // { name: '成华区', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + // { name: '武侯区', value: 122, percent: '10.6' }, + // { name: '龙泉驿区', value: 121, percent: '10.5' }, + // { name: '温江区', value: 120, percent: '10.4' }, + // { name: '新都区', value: 119, percent: '10.3' }, + // { name: '郫都区', value: 118, percent: '10.2' }, + // { name: '都江堰市', value: 117, percent: '10.1' } + // ]; + // console.log('使用模拟环卫人员区域数据'); + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name, + percentage: parseFloat(item.percent) || 0, + count: parseInt(item.value) || 0 + })); + + console.log('环卫人员区域数据成功:'); + setData(formattedData); + }, + onError: (error) => { + console.error('获取环卫人员区域数据出错:', error); + setData([]); + }, + apiName: '环卫人员区域', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 使用 useMemo 跟踪 rightPanelTime 的实际变化 + const memoizedRightPanelTime = useMemo(() => { + return { + type: mapState.rightPanelTime.type, + startTime: mapState.rightPanelTime.startTime, + endTime: mapState.rightPanelTime.endTime + }; + }, [ + mapState.rightPanelTime.type, + mapState.rightPanelTime.startTime, + mapState.rightPanelTime.endTime + ]); + + // 跟踪上一次的API参数,避免重复调用 + const prevApiParamsRef = useRef(''); + + // 在地图状态变化和Tab变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载环卫人员区域数据'); + return; + } + + // 参数签名,用于比较参数是否有实际变化 + const paramsSignature = JSON.stringify(params); + + // 检查参数是否真正变化,防止重复调用 + if (paramsSignature === prevApiParamsRef.current) { + console.log('环卫人员区域参数未变化,跳过重复加载'); + return; + } + + console.log('加载环卫人员区域数据,参数:', params); + // highFrequencyApi.callApi(params); + + // 更新上一次参数签名 + prevApiParamsRef.current = paramsSignature; + + }, [mapState.regionCode, memoizedRightPanelTime, currentTab, buildApiParams, highFrequencyApi]); + + return ( +
+ +
+ +
+
+ ) +} + +export default BridgeAreaDistribution; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceCategory/index.less b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceCategory/index.less new file mode 100644 index 0000000000000000000000000000000000000000..cc504c03919082f12c37466bef9035e7116a1798 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceCategory/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 252px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 0px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceCategory/index.tsx b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceCategory/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5f60b491331ed199bb8130fcc98c47b59a67ddd0 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceCategory/index.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface CarTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const BridgeMaintenanceCategory: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市政设施', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: 'I等', value: 456, percent: '97.2' }, + { name: 'II等', value: 400, percent: '83.5' }, + { name: 'III等', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载桥梁养护类别数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default BridgeMaintenanceCategory; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceLevel/index.less b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceLevel/index.less new file mode 100644 index 0000000000000000000000000000000000000000..cc504c03919082f12c37466bef9035e7116a1798 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceLevel/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 252px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 0px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceLevel/index.tsx b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceLevel/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6161564b5d7769ba453d6358ce1a23080a8a052b --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/BridgeMaintenanceLevel/index.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface CarTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const BridgeMaintenanceLevel: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市政设施', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: 'I等', value: 456, percent: '97.2' }, + { name: 'II等', value: 400, percent: '83.5' }, + { name: 'III等', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载桥梁养护等级数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default BridgeMaintenanceLevel; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadAreaDistribution/index.less b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadAreaDistribution/index.less new file mode 100644 index 0000000000000000000000000000000000000000..38e9a1a0cc5109e3c29f46ae4b77c8583f14635e --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadAreaDistribution/index.less @@ -0,0 +1,16 @@ +.container { + width: 530px; + height: 311px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + padding-bottom: 20px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + margin-top: 10px; + overflow: hidden; + } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadAreaDistribution/index.tsx b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadAreaDistribution/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7c1b07af388bf6d733753ca182bb587ce55c72a3 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadAreaDistribution/index.tsx @@ -0,0 +1,273 @@ +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import styles from './index.less'; +import HncyCard from '@/pages/Home_v_2504/components/common/Card' +import AreaBarList, { AreaBarItem } from '@/components/V2504/AreaBarList' +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs' +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import { getDistrictHighFrequencyArea } from '@/services/CityProblem'; +import { CarAreaProps } from '@/pages/Home_v_2504/components/SubPages/Environment/components/LeftContent/components/CarArea'; + +// 类型定义 +export interface RoadAreaDistributionProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; +} + +// 区域类型定义 +export type AreaType = 'all' | 'urban' | 'central' | 'county'; +const RoadAreaDistribution: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市政设施' +}) => { + + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 当前选中的区域类型 + const [currentTab, setCurrentTab] = useState('all'); + const currentTabRef = useLatestValue(currentTab); + + // 环卫人员区域数据 + // const [data, setData] = useState([]); + const [data, setData] = useState([ + { name: '锦江区', count: 456, percentage: 97.2 }, + { name: '金牛区', count: 400, percentage: 83.5 }, + { name: '成华区', count: 322, percentage: 70.8 }, + { name: '青羊区', count: 186, percentage: 65.6 }, + { name: '双流区', count: 152, percentage: 12.9 }, + { name: '武侯区', count: 122, percentage: 10.6 }, + { name: '龙泉驿区', count: 121, percentage: 10.5 }, + { name: '温江区', count: 120, percentage: 10.4 }, + { name: '新都区', count: 119, percentage: 10.3 }, + { name: '郫都区', count: 118, percentage: 10.2 }, + { name: '都江堰市', count: 117, percentage: 10.1 } + ]); + + // 处理Tab切换 + const handleTabChange = (tab: string) => { + setCurrentTab(tab as AreaType); + }; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 区域编码生成函数 + const getRegionCodes = (areaType: AreaType, regionCode: string) => { + // 默认所有区域 + if (areaType === 'all') { + return regionCode.length > 4 + ? regionCode + : regionCode === '5101' + ? '510104,510105,510106,510107,510108,510112,510113,510114,510115,510116,510117,510121,510129,510131,510132,510181,510182,510183,510184,510185' + : ''; + } + + // 城市新区 + if (areaType === 'urban') { + return '510112,510113,510114,510115,510116,510117'; + } + + // 中心城区 + if (areaType === 'central') { + return '510104,510105,510106,510107,510108'; + } + + // 县市新城 + if (areaType === 'county') { + return '510121,510129,510131,510132,510181,510182,510183,510184,510185'; + } + + return ''; + }; + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.leftPanelTime?.startTime || !currentMapState.leftPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.leftPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 获取区域编码列表 + const districtCodeList = getRegionCodes(currentTabRef.current, currentMapState.regionCode); + if (districtCodeList) { + params.districtCodeList = districtCodeList; + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, currentTabRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理环卫人员区域API调用 + const highFrequencyApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起环卫人员区域请求,参数:', params); + const response = await getDistrictHighFrequencyArea(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取环卫人员区域数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + setData([]); + return; + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseFloat(item.value) === 0 && parseFloat(item.percent) === 0)) { + // data = [ + // { name: '锦江区', value: 456, percent: '97.2' }, + // { name: '金牛区', value: 400, percent: '83.5' }, + // { name: '成华区', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + // { name: '武侯区', value: 122, percent: '10.6' }, + // { name: '龙泉驿区', value: 121, percent: '10.5' }, + // { name: '温江区', value: 120, percent: '10.4' }, + // { name: '新都区', value: 119, percent: '10.3' }, + // { name: '郫都区', value: 118, percent: '10.2' }, + // { name: '都江堰市', value: 117, percent: '10.1' } + // ]; + // console.log('使用模拟环卫人员区域数据'); + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name, + percentage: parseFloat(item.percent) || 0, + count: parseInt(item.value) || 0 + })); + + console.log('环卫人员区域数据成功:'); + setData(formattedData); + }, + onError: (error) => { + console.error('获取环卫人员区域数据出错:', error); + setData([]); + }, + apiName: '环卫人员区域', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 使用 useMemo 跟踪 rightPanelTime 的实际变化 + const memoizedRightPanelTime = useMemo(() => { + return { + type: mapState.rightPanelTime.type, + startTime: mapState.rightPanelTime.startTime, + endTime: mapState.rightPanelTime.endTime + }; + }, [ + mapState.rightPanelTime.type, + mapState.rightPanelTime.startTime, + mapState.rightPanelTime.endTime + ]); + + // 跟踪上一次的API参数,避免重复调用 + const prevApiParamsRef = useRef(''); + + // 在地图状态变化和Tab变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载环卫人员区域数据'); + return; + } + + // 参数签名,用于比较参数是否有实际变化 + const paramsSignature = JSON.stringify(params); + + // 检查参数是否真正变化,防止重复调用 + if (paramsSignature === prevApiParamsRef.current) { + console.log('环卫人员区域参数未变化,跳过重复加载'); + return; + } + + console.log('加载环卫人员区域数据,参数:', params); + // highFrequencyApi.callApi(params); + + // 更新上一次参数签名 + prevApiParamsRef.current = paramsSignature; + + }, [mapState.regionCode, memoizedRightPanelTime, currentTab, buildApiParams, highFrequencyApi]); + + return ( +
+ +
+ +
+
+ ) +} + +export default RoadAreaDistribution; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceCategory/index.less b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceCategory/index.less new file mode 100644 index 0000000000000000000000000000000000000000..cc504c03919082f12c37466bef9035e7116a1798 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceCategory/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 252px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 0px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceCategory/index.tsx b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceCategory/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..74e236fd1d9434a9dfc9b1707675e32b65f522fe --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceCategory/index.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface CarTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const RoadMaintenanceCategory: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市政设施', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: 'I等', value: 456, percent: '97.2' }, + { name: 'II等', value: 400, percent: '83.5' }, + { name: 'III等', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载道路养护类别数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default RoadMaintenanceCategory; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceLevel/index.less b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceLevel/index.less new file mode 100644 index 0000000000000000000000000000000000000000..cc504c03919082f12c37466bef9035e7116a1798 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceLevel/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 252px; + background: linear-gradient(180.00deg, rgba(77, 107, 178, 0.3), rgba(8, 153, 255, 0.01) 100%); + border-radius: 15px; + // box-shadow: inset 0px 0px 23px 0px rgba(31, 87, 222, 0.5); + // padding-bottom: 10px; + display: flex; + flex-direction: column; + } + + .content { + flex: 1; + overflow: hidden; + padding: 0px 20px 0 20px; + } + + // .contentThin{ + // padding: 4px 18px 0 18px; + // } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceLevel/index.tsx b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceLevel/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3bbcd9c115979e520df33e7c9ede170cd2fd9782 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/components/RoadMaintenanceLevel/index.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useState, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import ChartWithLegend, { ChartDataItem } from '@/components/V2504/ChartWithLegend'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getSourceSystemRank } from '@/services/CityProblem'; +import useApiControl, { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; + +interface CarTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; +} + +const RoadMaintenanceLevel: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市政设施', + isThinLayout = true, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)', 'rgb(71, 223, 155)', 'rgb(97, 141, 255)']; + + // 转换日期类型为API参数 + const translateDateType = useCallback((type: string) => { + switch (type) { + case 'year': return '1'; + case 'month': return '2'; + case 'day': return '3'; + case 'range': return '4'; + default: return '2'; // 默认月视图 + } + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = currentMapState.rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(currentMapState.rightPanelTime.startTime); + params.customizeEnd = formatDateTime(currentMapState.rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(currentMapState.rightPanelTime.startTime); + } + + // 处理区域参数 + if (currentMapState.regionCode === '5101') { + // 成都,这两个参数就不传 + params.districtCode = undefined; + params.streetCode = undefined; + } else if (currentMapState.regionCode.length === 6) { + // 区县级别 + params.districtCode = currentMapState.regionCode; + } else if (currentMapState.regionCode.length === 9) { + // 街道级别 + params.districtCode = currentMapState.regionCode.substring(0, 6); + params.streetCode = currentMapState.regionCode; + } + + // 使用传入的dataTypeKey获取对应的subTypeCode + params.subTypeCode = useDataType(dataTypeKey); + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey]); + + // 使用useApiControl管理问题来源API调用 + const sourceSystemRankApi = useApiControl({ + apiFunction: async (params) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: 'I等', value: 456, percent: '97.2' }, + { name: 'II等', value: 400, percent: '83.5' }, + { name: 'III等', value: 322, percent: '70.8' }, + // { name: '青羊区', value: 186, percent: '65.6' }, + // { name: '双流区', value: 152, percent: '12.9' }, + ]; + // console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 如果接口返回数据都是0,生成模拟数据 + // if (data.every(item => parseInt(item.value) === 0 && parseFloat(item.percent) === 0)) { + + // } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name || '未知来源', + value: parseInt(item.value) || 0, + percentage: parseFloat(item.percent) || 0 + })); + + console.log('问题来源数据成功:', formattedData); + setData(formattedData); + }, + onError: (error) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000 // 缓存5秒,避免频繁刷新时重复请求 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载问题来源数据'); + return; + } + + console.log('加载道路养护等级数据,参数:', params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, buildApiParams, sourceSystemRankApi]); + + const totalValue = data.reduce((sum, item) => sum + (item.value || 0), 0); + + return ( +
+ +
+ +
+
+ ); +}; + +export default RoadMaintenanceLevel; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/index.tsx b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/index.tsx index fcd6258cd4b99ae0b4a6ab90d610f86e21de500f..cac3d4317e681390a86b711a2a0f5613ac8cf8e2 100644 --- a/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/index.tsx +++ b/src/pages/Home_v_2504/components/SubPages/Municipal/components/LeftContent/index.tsx @@ -1,7 +1,12 @@ import React from 'react'; import styles from './index.less'; import PanelTitle from '@/pages/Home_v_2504/components/common/PanelTitle'; - +import RoadMaintenanceLevel from './components/RoadMaintenanceLevel'; +import BridgeMaintenanceLevel from './components/BridgeMaintenanceLevel'; +import RoadMaintenanceCategory from './components/RoadMaintenanceCategory'; +import BridgeMaintenanceCategory from './components/BridgeMaintenanceCategory'; +import RoadAreaDistribution from './components/RoadAreaDistribution'; +import BridgeAreaDistribution from './components/BridgeAreaDistribution'; /** * 市政设施左侧内容组件 */ @@ -11,10 +16,15 @@ const LeftContent: React.FC = () => { {/* 标题 */}
-
+
-

此处为市政设施监管左侧内容区域

+ + + + + +
);