diff --git a/src/assets/images/bgIcon1.png b/src/assets/images/V-2504/bgIcon1.png similarity index 100% rename from src/assets/images/bgIcon1.png rename to src/assets/images/V-2504/bgIcon1.png diff --git a/src/assets/images/bgIcon2.png b/src/assets/images/V-2504/bgIcon2.png similarity index 100% rename from src/assets/images/bgIcon2.png rename to src/assets/images/V-2504/bgIcon2.png diff --git a/src/assets/images/bgIcon3.png b/src/assets/images/V-2504/bgIcon3.png similarity index 100% rename from src/assets/images/bgIcon3.png rename to src/assets/images/V-2504/bgIcon3.png diff --git a/src/assets/images/bgIcon4.png b/src/assets/images/V-2504/bgIcon4.png similarity index 100% rename from src/assets/images/bgIcon4.png rename to src/assets/images/V-2504/bgIcon4.png diff --git a/src/assets/images/bgIcon5.png b/src/assets/images/V-2504/bgIcon5.png similarity index 100% rename from src/assets/images/bgIcon5.png rename to src/assets/images/V-2504/bgIcon5.png diff --git a/src/components/V2504/AreaBarList/index.less b/src/components/V2504/AreaBarList/index.less index 36f5fa27063494e856fa8ec3a96626fe11ccb016..d358270b9bc8922941b4d8af4bbad759da4c1b01 100644 --- a/src/components/V2504/AreaBarList/index.less +++ b/src/components/V2504/AreaBarList/index.less @@ -24,6 +24,9 @@ .thinItemWrapper { margin-bottom: -5px; } +.widePaddingItemWrapper { + margin-bottom: 30px; +} .itemHeader { display: flex; diff --git a/src/components/V2504/AreaBarList/index.tsx b/src/components/V2504/AreaBarList/index.tsx index 17dcd1bfc8e64096a1993c4f74cc5b6eac137279..74bf534a58e64271db8d1f54ecf49da808ff2feb 100644 --- a/src/components/V2504/AreaBarList/index.tsx +++ b/src/components/V2504/AreaBarList/index.tsx @@ -29,6 +29,7 @@ export interface AreaBarListProps { percentageFixed?: number; valueStyle?: React.CSSProperties; isThinProgress?: boolean; + isWidePadding?: boolean; } const AreaBarList: React.FC = ({ @@ -44,6 +45,7 @@ const AreaBarList: React.FC = ({ percentageFixed = 2, valueStyle = {}, isThinProgress = false, + isWidePadding = false, }) => { const percentageValue = (value: number) => { return Number(value ? Number(value).toFixed(percentageFixed) : 0); @@ -56,6 +58,7 @@ const AreaBarList: React.FC = ({ key={index} className={classNames(styles.itemWrapper, { [styles.thinItemWrapper]: isThinProgress, + [styles.widePaddingItemWrapper]: isWidePadding, })} onClick={() => onClick && onClick(item, index)} > diff --git a/src/components/V2504/ChartWithLegend/index.less b/src/components/V2504/ChartWithLegend/index.less index 2d714e1c15037b20a8af731e03f4d9da725f77f5..e6aceba783f0d2c184fbcf5b5f2b12ba66873eab 100644 --- a/src/components/V2504/ChartWithLegend/index.less +++ b/src/components/V2504/ChartWithLegend/index.less @@ -95,10 +95,12 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - min-width: 120px; + min-width: 100px; + max-width: 103px; } .shortName{ min-width: 80px; + max-width: 103px; } .valueSection { @@ -115,7 +117,7 @@ font-family: DIN; font-size: 20px; font-weight: 700; - margin-left: 14px; + margin-left:8px; } .shortValue{ margin-left: 2px; diff --git a/src/constants/dataTypes.ts b/src/constants/dataTypes.ts index c7d223d4d4dba65c6a34584cca3d2dccae58555d..474c378081162ce54e81b847aae74c192acf2dc5 100644 --- a/src/constants/dataTypes.ts +++ b/src/constants/dataTypes.ts @@ -200,6 +200,9 @@ export const INDUSTRY_PAGE_IDS = { MUNICIPAL: 'municipal', LANDSCAPE_LIGHTING: 'landscapeLighting', LAW_ENFORCEMENT: 'lawEnforcement', + LAW_ENFORCEMENT_PUNISHMENT: 'lawEnforcementPunishment', + LAW_ENFORCEMENT_COORDINATION: 'lawEnforcementCoordination', + LAW_ENFORCEMENT_PATROL: 'lawEnforcementPatrol', DOMESTIC_WASTE: 'domesticWaste', CONSTRUCTION_WASTE: 'constructionWaste', CITY_APPEARANCE: 'cityAppearance', diff --git a/src/pages/Home_v_2504/components/MapStateContext.tsx b/src/pages/Home_v_2504/components/MapStateContext.tsx index b038848c4c1311217f3bd5c019c8c848e5f59c16..a489ae7fc7e2b884dda8e2f33d62073df39c5bcc 100644 --- a/src/pages/Home_v_2504/components/MapStateContext.tsx +++ b/src/pages/Home_v_2504/components/MapStateContext.tsx @@ -960,6 +960,12 @@ export const useDataType = (typeStr: string) => { return DATA_TYPE.DOMESTIC_WASTE.WASTE_EVENT; case '建筑垃圾': return DATA_TYPE.CONSTRUCTION_WASTE.CONSTRUCTION_EVENT; + case '行政处罚': + return DATA_TYPE.LAW_ENFORCEMENT.PUNISHMENT; + case '市区协同': + return DATA_TYPE.LAW_ENFORCEMENT.COORDINATION; + case '日常巡查': + return DATA_TYPE.LAW_ENFORCEMENT.PATROL; default: return DATA_TYPE.RESTAURANT_OIL.OIL_SMOKE_EVENT; diff --git a/src/pages/Home_v_2504/components/SubPages/DomesticWaste/components/LeftContent/components/DisposalTrend/index.tsx b/src/pages/Home_v_2504/components/SubPages/DomesticWaste/components/LeftContent/components/DisposalTrend/index.tsx index ef7fc5e7a658882d84ae113b302e84fa02f0ad4e..4bab7dbc8d18c9f427bf541197d167de3e8718c6 100644 --- a/src/pages/Home_v_2504/components/SubPages/DomesticWaste/components/LeftContent/components/DisposalTrend/index.tsx +++ b/src/pages/Home_v_2504/components/SubPages/DomesticWaste/components/LeftContent/components/DisposalTrend/index.tsx @@ -63,8 +63,8 @@ const DisposalTrend: React.FC = () => { data={mockData} unitText="单位:万吨" lineColor="rgb(32, 214, 201)" - lineColorStop1="rgba(32, 214, 201, 0)" - lineColorStop2="rgba(32, 214, 201, 0.36)" + lineColorStop1="rgba(32, 214, 201, 0.36)" + lineColorStop2="rgba(32, 214, 201, 0)" // lineColor="rgb(136, 238, 248)" // lineColorStop1="rgba(136, 238, 248, 0)" // lineColorStop2="rgba(136, 238, 248, 0.36)" diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseHandlingQuantity/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseHandlingQuantity/index.less new file mode 100644 index 0000000000000000000000000000000000000000..f9937cafe03370cae89674f313284de7c1e97b52 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseHandlingQuantity/index.less @@ -0,0 +1,17 @@ +.container { + width: 530px; + // height: 380px; + height: 485px; + 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: 0.95; + margin-top: 20px; + overflow: hidden; +} \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseHandlingQuantity/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseHandlingQuantity/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0f1540588308dac6addb06c85e6e0e996678856b --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseHandlingQuantity/index.tsx @@ -0,0 +1,241 @@ +import React, { useState, useEffect, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import AreaBarList, { AreaBarItem } from '@/components/V2504/AreaBarList'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getDistrictHighFrequencyArea } from '@/services/CityProblem'; +import { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +// 类型定义 +export interface CaseHandlingQuantityProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; + pageId?: string; +} + +// 区域类型定义 +export type AreaType = 'all' | 'urban' | 'central' | 'county'; + +// 区域级别定义 +export enum RegionLevelEnum { + CITY = '1', // 市级 + DISTRICT = '2', // 区县级 + STREET = '3', // 街道级 + GRID = '4', // 网格级 +} + +// 区域编码生成函数 +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 ''; +}; + +const CaseHandlingQuantity: React.FC = ({ + dateType, + dateRange, + isThinLayout = false, + dataTypeKey = '市区协同', + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_COORDINATION, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 当前选中的区域类型 + const [currentTab, setCurrentTab] = useState('all'); + const currentTabRef = useLatestValue(currentTab); + + // 办案数量数据 + 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'; // 默认月视图 + } + }, []); + + // 处理Tab切换 + const handleTabChange = (tab: string) => { + setCurrentTab(tab as AreaType); + }; + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理办案数量API调用 + const highFrequencyApi = usePageAwareApi({ + 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; + } + + let isUsingMock = true; + const defaultPercentage = isUsingMock ? 99 : 0; + const defaultValue = isUsingMock ? 200 : 0; + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name, + percentage: parseFloat(item.percent) || defaultPercentage, + count: parseInt(item.value) || defaultValue + })); + + console.log('办案数量数据成功:'); + setData(formattedData); + }, + onError: (error) => { + console.error('获取办案数量数据出错:', error); + setData([]); + }, + apiName: '办案数量', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + pageId: pageId, // 传入页面ID用于页面感知 + }); + + // 在地图状态变化和Tab变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载办案数量数据'); + return; + } + + // 调用API - 现在usePageAwareApi内部会处理参数比较和页面状态 + highFrequencyApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, currentTab, buildApiParams, highFrequencyApi]); + + return ( +
+ +
+ +
+
+ ); +}; + +export default CaseHandlingQuantity; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseTrend/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseTrend/index.less new file mode 100644 index 0000000000000000000000000000000000000000..3bb7cc1a2d2db543d44708ac5a6b9d80a98aa665 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseTrend/index.less @@ -0,0 +1,12 @@ +.container { + width: 1078px; + height: 224px; + background: linear-gradient(180deg, 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); +} + +.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/LawEnforcementCoordination/components/RightContent/CaseTrend/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseTrend/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8463e32fbcb408b5447c21c9d419cec626efc945 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/CaseTrend/index.tsx @@ -0,0 +1,305 @@ +import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import SmoothLineChart from '@/components/V2504/SmoothLineChart'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getEventTrends } from '@/services/CityProblem'; +import { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +// 类型定义 +interface CaseTrendProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + pageId?: string; // 新增页面ID参数 +} + +const CaseTrend: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市区协同', + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_COORDINATION, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 图表数据 + const [data, setData] = useState<{ time: string; value: number }[]>([]); + + // 转换日期类型为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'; // 默认月视图 + } + }, []); + + // 转换时间格式 - 参考LeftContent中的translateTrendTime函数 + const translateTrendTime = useCallback((inputDate: string | number) => { + if (typeof inputDate === 'string') { + // 处理类似'2025-11'的格式 + if (inputDate.includes('-') && inputDate.length === 7) { + const month = parseInt(inputDate.substring(5, 7)); + return `${month}月`; + } + // 处理类似'20250425'的格式 + // if (inputDate.length === 8) { + // const month = parseInt(inputDate.substring(4, 6)); + // const day = parseInt(inputDate.substring(6, 8)); + // return `${month}月${day}日`; + // } + // 处理YYYY-MM-DD格式 + if (inputDate.includes('-') && inputDate.length === 10) { + const dateParts = inputDate.split('-'); + if (dateParts.length >= 3) { + const month = parseInt(dateParts[1]); + const day = parseInt(dateParts[2]); + return `${month}月${day}日`; + } + } + // 处理类似"03"的格式 + if (inputDate.length === 2) { + if (inputDate === '23') { + return '23:59:59'; + } + return `${inputDate.padStart(2, '0')}:00:00`; + } + // console.log('inputDate:', inputDate); + return inputDate.substring(0, 10); + } + // 处理number类型 + if (typeof inputDate === 'number') { + if (inputDate === 23) { + return '23:59:59'; + } + return `${inputDate.toString().padStart(2, '0')}:00`; + } + return inputDate; + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理问题趋势API调用 + const eventTrendsApi = usePageAwareApi({ + apiFunction: async (params: any) => { + console.log('发起问题趋势请求,参数:', params); + const response = await getEventTrends(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题趋势数据失败'); + }, + onSuccess: (data: any) => { + if (!data || !Array.isArray(data)) { + setData([]); + return; + } + console.log('onSuccess:'); + + let isUseMockData = true; + if (isUseMockData) { + // setData(mockData); + data = mockData; + } + + const isSupplementData = false; + // 如果是月数据,补充到月底 '2025-05-06' + if (data[0].name.includes('-') && data[0].name.length === 10 && isSupplementData) { + // 获取当前日期 + const today = new Date(); + const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 1); + // console.log('lastDay:', lastDay); + + // 生成完整日期范围 + const fullData = [...data]; // 先复制已有数据 + + // 从明天开始补充数据 + for (let d = new Date(today); d <= lastDay; d.setDate(d.getDate() + 1)) { + // 跳过今天及之前的日期 + if (d <= today) continue; + + const dateStr = d.toISOString().slice(0, 10).replace(/-/g, '-'); + fullData.push({ + name: dateStr, + value: '0' + }); + } + data = fullData; + // console.log('补充到月底的数据:', data); + } + + // 如果是小时数据,补充到23点 + if (data[0].name.length === 2 && isSupplementData) { + // 获取当前小时 + const currentHour = new Date().getHours(); + // 生成完整小时范围 + const fullData = [...data]; // 先复制已有数据 + + // 从下一小时开始补充数据 + for (let h = currentHour + 1; h <= 23; h++) { + const hourStr = h.toString().padStart(2, '0'); + fullData.push({ + name: hourStr, + value: '0' + }); + } + data = fullData; + } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + time: translateTrendTime(item.name), + value: parseInt(item.value) || 0 + })); + + console.log('问题趋势数据成功:'); + setData(formattedData); + }, + onError: (error: any) => { + console.error('获取问题趋势数据出错:', error); + // 出错时使用空数据 + setData([]); + }, + apiName: '问题趋势', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + enableDebug: false, + pageId: pageId, // 添加页面ID以启用页面感知 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,暂不加载问题趋势数据'); + return; + } + + console.log(`加载${pageId}页面问题趋势数据,参数:`, params); + eventTrendsApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, buildApiParams, eventTrendsApi, pageId]); + + + // Mock data for the chart + const mockData: { name: string; value: number }[] = [ + { name: '2025-04-01', value: 145 }, + { name: '2025-04-02', value: 160 }, + { name: '2025-04-03', value: 155 }, + { name: '2025-04-04', value: 165 }, + { name: '2025-04-05', value: 175 }, + { name: '2025-04-06', value: 185 }, + { name: '2025-04-07', value: 180 }, + { name: '2025-04-08', value: 190 }, + { name: '2025-04-09', value: 195 }, + { name: '2025-04-10', value: 205 }, + { name: '2025-04-11', value: 310 }, + { name: '2025-04-12', value: 425 }, + { name: '2025-04-13', value: 330 }, + { name: '2025-04-14', value: 320 }, + { name: '2025-04-15', value: 265 }, + { name: '2025-04-16', value: 255 }, + { name: '2025-04-17', value: 240 }, + { name: '2025-04-18', value: 235 }, + { name: '2025-04-19', value: 210 }, + { name: '2025-04-20', value: 215 }, + { name: '2025-04-21', value: 225 }, + { name: '2025-04-22', value: 230 }, + { name: '2025-04-23', value: 235 }, + { name: '2025-04-24', value: 240 }, + { name: '2025-04-25', value: 245 }, + { name: '2025-04-26', value: 250 }, + { name: '2025-04-27', value: 255 }, + { name: '2025-04-28', value: 260 }, + { name: '2025-04-29', value: 265 }, + { name: '2025-04-30', value: 270 }, + ]; + + + return ( +
+ +
+ +
+
+ ); +}; + +export default CaseTrend; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/HighFrequencyType/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/HighFrequencyType/index.less new file mode 100644 index 0000000000000000000000000000000000000000..f9937cafe03370cae89674f313284de7c1e97b52 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/HighFrequencyType/index.less @@ -0,0 +1,17 @@ +.container { + width: 530px; + // height: 380px; + height: 485px; + 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: 0.95; + margin-top: 20px; + overflow: hidden; +} \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/HighFrequencyType/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/HighFrequencyType/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..64762f1f10deb2f3266e33db534c764273e8ff04 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/HighFrequencyType/index.tsx @@ -0,0 +1,230 @@ +import React, { useState, useEffect, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import AreaBarList, { AreaBarItem } from '@/components/V2504/AreaBarList'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getDistrictHighFrequencyArea } from '@/services/CityProblem'; +import { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +// 类型定义 +export interface HighFrequencyTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + pageId?: string; +} + +// 区域类型定义 +export type AreaType = 'all' | 'urban' | 'central' | 'county'; + +// 区域级别定义 +export enum RegionLevelEnum { + CITY = '1', // 市级 + DISTRICT = '2', // 区县级 + STREET = '3', // 街道级 + GRID = '4', // 网格级 +} + +// 区域编码生成函数 +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 ''; +}; + +const HighFrequencyType: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市区协同', + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_COORDINATION, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 当前选中的区域类型 + const [currentTab, setCurrentTab] = useState('all'); + const currentTabRef = useLatestValue(currentTab); + + // 高发区域数据 + 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'; // 默认月视图 + } + }, []); + + // 处理Tab切换 + const handleTabChange = (tab: string) => { + setCurrentTab(tab as AreaType); + }; + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理高发区域API调用 + const highFrequencyApi = usePageAwareApi({ + 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; + } + + let isUsingMock = true; + const defaultPercentage = isUsingMock ? 99 : 0; + const defaultValue = isUsingMock ? 200 : 0; + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name, + percentage: parseFloat(item.percent) || defaultPercentage, + count: parseInt(item.value) || defaultValue + })); + + console.log('高发区域数据成功:'); + setData(formattedData); + }, + onError: (error) => { + console.error('获取高发区域数据出错:', error); + setData([]); + }, + apiName: '高发类型', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + pageId: pageId, // 传入页面ID用于页面感知 + }); + + // 在地图状态变化和Tab变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载高发类型数据'); + return; + } + + // 调用API - 现在usePageAwareApi内部会处理参数比较和页面状态 + highFrequencyApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, currentTab, buildApiParams, highFrequencyApi]); + + return ( +
+ +
+ +
+
+ ); +}; + +export default HighFrequencyType; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/LineCharts/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/LineCharts/index.less deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/LineCharts/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/LineCharts/index.tsx deleted file mode 100644 index 06aed37d131299acae84b745818edbc811e4b646..0000000000000000000000000000000000000000 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/LineCharts/index.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import * as echarts from 'echarts'; -import React, { useEffect, useRef } from 'react' - -type Props = { - data: string[] -} - -export default function lineCharts({ - data -}: Props) { - - const chartRef = useRef(null); - - useEffect(() => { - const chart = echarts.init(chartRef.current!); - const option = { - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross', - label: { - backgroundColor: '#6a7985' - } - } - }, - grid: { - left: '3%', - right: '0%', - top: '15%', - bottom: '15%', - containLabel: true - }, - xAxis: [ - { - type: 'category', - boundaryGap: false, - data: data, - axisLine: { - show: false, - }, - axisLabel: { - fontSize: 16, - fontWeight: 400, - alignMinLabel: 'left', - alignMaxLabel: 'right', - interval: (index: number) => { - return index === 0 || index === data.length - 1; - }, - }, - } - ], - yAxis: [ - { - type: 'value', - name: '单位:件', - nameTextStyle: { - color: '#BCCEE9', - fontSize: 14, - fontWeight: 400 - }, - splitLine: { - show: false - }, - axisLine: { - show: false - }, - axisLabel: { - show: false - } - } - ], - series: [ - { - name: '案件数量', - type: 'line', - stack: 'Total', - smooth: true, - lineStyle: { - color: '#01FFF6' - }, - itemStyle: { - color: '#01FFF6' - }, - showSymbol: false, - areaStyle: { - opacity: 0.24, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { - offset: 0, - color: '#88EEF8' - }, - { - offset: 1, - color: 'rgba(136, 238, 248, 0)' - } - ]) - }, - // 随机生成30个数字类型数据 - data: Array.from({ length: 30 }, () => - Math.floor(Math.random() * 1000) - ) - }, - ] - }; - chart.setOption(option); - - return () => chart.dispose(); // 组件卸载时销毁 - }, [data]); - - return ( -
- ) -} \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/index.less deleted file mode 100644 index 0682fe4aa38a50f7851e00cc3ee7a88457ae8b10..0000000000000000000000000000000000000000 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/index.less +++ /dev/null @@ -1,27 +0,0 @@ -.middleContent { - .statistic { - display: flex; - align-items: center; - gap: 25px; - - .statistic_item { - display: flex; - align-items: center; - justify-content: flex-start; - width: 157px; - height: 70px; - padding-left: 20px; - border-radius: 10px; - background: rgba(57, 122, 183, 0.2); - } - - .sp { - width: 242px; - } - } - - .line_chart { - width: 100%; - margin-top: 33px; - } -} \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/index.tsx deleted file mode 100644 index 9ea2016522813ef1127af5fd36bac163af1cd774..0000000000000000000000000000000000000000 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/MiddleContent/index.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import classNames from 'classnames' -import React, { CSSProperties, useEffect, useMemo } from 'react' - -import LineCharts from './LineCharts'; -import HncyCard from '@/pages/Home_v_2504/components/common/Card' -import DescriptionItem from '@/components/DescriptionItem' -import bgIcon1 from '@/assets/images/bgIcon1.png' -import bgIcon2 from '@/assets/images/bgIcon2.png' -import bgIcon3 from '@/assets/images/bgIcon3.png' -import bgIcon4 from '@/assets/images/bgIcon4.png' -import bgIcon5 from '@/assets/images/bgIcon5.png' - -import styles from './index.less' - -type statisticProps = { - value: number; - name: string; - unit: string; - bgIcon: string; - iconSize: string; - valueStyle?: CSSProperties; - unitStyle?: CSSProperties; - labelStyle?: CSSProperties; - direction?: 'vertical' | 'horizontal'; -}[] - -export default function MiddleContent() { - - const statistic: statisticProps = useMemo(() => { - return [ - { - value: 1000, - name: '立案', - unit: '件', - bgIcon: bgIcon1, - iconSize: '46px 52px', - valueStyle: valueStyle, - unitStyle: unitStyle, - labelStyle: labelStyle, - direction: 'vertical', - }, { - value: 1000, - name: '处置中', - unit: '件', - bgIcon: bgIcon2, - iconSize: '44px 50px', - valueStyle: { - ...valueStyle, - background: 'linear-gradient(180.00deg, rgb(170, 255, 246),rgb(10, 192, 167))', - // @ts-ignore - webkitBackgroundClip: 'text', - WebkitTextFillColor: 'transparent', - backgroundClip: 'text', - textFillColor: 'transparent', - }, - unitStyle: unitStyle, - labelStyle: labelStyle, - direction: 'vertical' - }, { - value: 1000, - name: '超时', - unit: '件', - bgIcon: bgIcon3, - iconSize: '52px 52px', - valueStyle: { - ...valueStyle, - color: '#FF4F4F', - }, - unitStyle: unitStyle, - labelStyle: labelStyle, - direction: 'vertical' - }, { - value: 1000, - name: '已办结', - unit: '件', - bgIcon: bgIcon4, - iconSize: '48px 48px', - valueStyle: valueStyle, - unitStyle: unitStyle, - labelStyle: { - ...labelStyle, - marginRight: 30 - }, - direction: 'horizontal' - }, { - value: 88.76, - name: '办结率', - unit: '%', - bgIcon: bgIcon5, - iconSize: '49px 49px', - valueStyle: valueStyle, - unitStyle: unitStyle, - labelStyle: { - ...labelStyle, - marginRight: 30 - }, - direction: 'horizontal' - }, - ] - }, []) - - - - useEffect(() => { - - }, []) - - return ( -
-
- { - statistic.map(({ bgIcon, iconSize, ...rest }, index) => { - return ( -
2 && styles.sp)} - style={{ - backgroundImage: `url(${bgIcon})`, - backgroundSize: iconSize, - backgroundRepeat: 'no-repeat', - backgroundPosition: '100%', - }} - > - -
- ) - }) - } -
-
- - - -
-
- ) -} - -const valueStyle: CSSProperties = { - fontSize: 28, - fontWeight: 700, - lineHeight: '26px', -} - -const unitStyle: CSSProperties = { - fontSize: 16, - fontWeight: 400, - lineHeight: '21px', -} - -const labelStyle: CSSProperties = { - fontSize: 16, - fontWeight: 400, - lineHeight: '21px', -} \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/StatisticsCards/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/StatisticsCards/index.less new file mode 100644 index 0000000000000000000000000000000000000000..9b367c73bc3c8d13e01751133f36a97642f1c402 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/StatisticsCards/index.less @@ -0,0 +1,55 @@ +.container { + width: 1078px; + height: 107px; + 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: 20px 0 0 16px; +} + +.statistic { + display: flex; + align-items: center; + gap: 20px; + + .statistic_item { + display: flex; + align-items: center; + justify-content: flex-start; + width: 157px; + height: 70px; + padding-left: 20px; + border-radius: 10px; + background: rgba(57, 122, 183, 0.2); + } + + .sp { + width: 242px; + } +} + +.row { + display: flex; + + & + .row { + margin-top: 15px; + } +} + +// .smallCard { +// width: 157px; +// height: 70px; + +// & + .smallCard { +// margin-left: 13px; +// } +// } + +// .largeCard { +// width: 242px; +// height: 70px; + +// & + .largeCard { +// margin-left: 15px; +// } +// } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/StatisticsCards/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/StatisticsCards/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fdad26a8af6afce36e320da598d57ab9ef17d5b1 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/StatisticsCards/index.tsx @@ -0,0 +1,330 @@ +import React, { useEffect, useState, useCallback, useRef, useMemo, CSSProperties } from 'react'; +import StatCard from '@/components/V2504/StatCard'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getDisposeStats } from '@/services/CityProblem'; +import { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; + +// Import stat card background images +import cardBg1 from '@/assets/images/V-2504/statcard-bg-1.png'; +import cardBg2 from '@/assets/images/V-2504/statcard-bg-2.png'; +import cardBg3 from '@/assets/images/V-2504/statcard-bg-3.png'; +import cardBg4 from '@/assets/images/V-2504/statcard-bg-4.png'; +import cardBg5 from '@/assets/images/V-2504/statcard-bg-5.png'; + +import bgIcon1 from '@/assets/images/V-2504/bgIcon1.png' +import bgIcon2 from '@/assets/images/V-2504/bgIcon2.png' +import bgIcon3 from '@/assets/images/V-2504/bgIcon3.png' +import bgIcon4 from '@/assets/images/V-2504/bgIcon4.png' +import bgIcon5 from '@/assets/images/V-2504/bgIcon5.png' +import DescriptionItem from '@/components/DescriptionItem'; +import classNames from 'classnames'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +export interface StatisticsCardsProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + pageId?: string; // 新增页面ID参数 +} + +type statisticProps = { + value: number; + name: string; + unit: string; + bgIcon: string; + iconSize: string; + valueStyle?: CSSProperties; + unitStyle?: CSSProperties; + labelStyle?: CSSProperties; + direction?: 'vertical' | 'horizontal'; +}[] + +// 案件情况数据结构 +interface DisposeStatsData { + accept: { name: string; code: string; value: number }; + disposing: { name: string; code: string; value: number }; + overdue: { name: string; code: string; value: number }; + close: { name: string; code: string; value: number }; + closeRate: { name: string; code: string; value: number }; +} + +const StatisticsCards: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '市区协同', + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_COORDINATION, +}) => { + // 地图状态 + const { mapState } = useMapState(); + // 使用ref存储最新的mapState,避免闭包问题 + const mapStateRef = useLatestValue(mapState); + + // 案件情况统计数据 + const [statsData, setStatsData] = useState({ + caseCount: 0, // 立案 + processingCount: 0, // 处置中 + overtimeCount: 0, // 超时 + completedCount: 0, // 已办结 + completionRate: 0, // 办结率 + }); + + // 转换日期类型为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 formatApiParams = useCallback((params: any) => { + const formattedParams = { ...params }; + + // 确保时间字段包含完整的时间部分 + if (formattedParams.time) { + formattedParams.time = formatDateTime(formattedParams.time); + } + + if (formattedParams.customizeStart) { + formattedParams.customizeStart = formatDateTime(formattedParams.customizeStart); + } + + if (formattedParams.customizeEnd) { + formattedParams.customizeEnd = formatDateTime(formattedParams.customizeEnd, true); + } + + return formattedParams; + }, []); + + // 使用usePageAwareApi管理案件情况API调用 + const disposeStatsApi = usePageAwareApi({ + apiFunction: async (params: any) => { + const response = await getDisposeStats(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取案件情况数据失败'); + }, + onSuccess: (data: DisposeStatsData) => { + if (!data) return; + + // 转换接口返回的数据格式 + setStatsData({ + caseCount: data.accept?.value || 0, + processingCount: data.disposing?.value || 0, + overtimeCount: data.overdue?.value || 0, + completedCount: data.close?.value || 0, + completionRate: data.closeRate?.value || 0, + }); + + console.log('案件情况数据成功:', data); + }, + onError: (error: any) => { + console.error('获取案件情况数据出错:', error); + }, + formatParams: formatApiParams, + apiName: '案件情况', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + enableDebug: false, + pageId: pageId, // 添加页面ID以启用页面感知 + }); + + // 构建API参数函数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType), + subTypeCode: useDataType(dataTypeKey) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = rightPanelTime.startTime; + params.customizeEnd = rightPanelTime.endTime; + } else { + // 年、月、日视图使用time参数 + params.time = 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; + } + + return params; + }, [mapStateRef, dateType, translateDateType, dataTypeKey, pageId]); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,暂不加载案件情况数据'); + return; + } + + console.log(`加载${pageId}页面案件情况数据,参数:`, params); + disposeStatsApi.callApi(params); + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, buildApiParams, disposeStatsApi, pageId]); + + const valueStyle: CSSProperties = { + fontSize: 28, + fontWeight: 700, + lineHeight: '28px', + } + + const unitStyle: CSSProperties = { + fontSize: 16, + fontWeight: 400, + lineHeight: '21px', + } + + const labelStyle: CSSProperties = { + fontSize: 16, + fontWeight: 400, + lineHeight: '21px', + } + + const labelVerticalStyle: CSSProperties = { + ...labelStyle, + marginTop: '4px', + } + + const statistic: statisticProps = useMemo(() => { + return [ + { + value: statsData.caseCount, + name: '立案', + unit: '件', + bgIcon: bgIcon1, + iconSize: '46px 52px', + valueStyle: valueStyle, + unitStyle: unitStyle, + labelStyle: labelVerticalStyle, + direction: 'vertical', + }, { + value: statsData.processingCount, + name: '处置中', + unit: '件', + bgIcon: bgIcon2, + iconSize: '44px 50px', + valueStyle: { + ...valueStyle, + background: 'linear-gradient(180.00deg, rgb(170, 255, 246),rgb(10, 192, 167))', + // @ts-ignore + webkitBackgroundClip: 'text', + WebkitTextFillColor: 'transparent', + backgroundClip: 'text', + textFillColor: 'transparent', + }, + unitStyle: unitStyle, + labelStyle: labelVerticalStyle, + direction: 'vertical' + }, { + value: statsData.overtimeCount, + name: '超时', + unit: '件', + bgIcon: bgIcon3, + iconSize: '52px 52px', + valueStyle: { + ...valueStyle, + color: '#FF4F4F', + }, + unitStyle: unitStyle, + labelStyle: labelVerticalStyle, + direction: 'vertical' + }, { + value: statsData.completedCount, + name: '已办结', + unit: '件', + bgIcon: bgIcon4, + iconSize: '48px 48px', + valueStyle: valueStyle, + unitStyle: unitStyle, + labelStyle: { + ...labelStyle, + marginRight: 30 + }, + direction: 'horizontal' + }, { + value: statsData.completionRate, + name: '办结率', + unit: '%', + bgIcon: bgIcon5, + iconSize: '49px 49px', + valueStyle: valueStyle, + unitStyle: unitStyle, + labelStyle: { + ...labelStyle, + marginRight: 30 + }, + direction: 'horizontal' + }, + ] +}, []) + + return ( +
+
+ { + statistic.map(({ bgIcon, iconSize, ...rest }, index) => { + return ( +
2 && styles.sp)} + style={{ + backgroundImage: `url(${bgIcon})`, + backgroundSize: iconSize, + backgroundRepeat: 'no-repeat', + backgroundPosition: '96%', + }} + > + +
+ ) + }) + } +
+
+ ); +}; + +export default StatisticsCards; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.less index b99d3db91137dab63cfa10ffc0ff27d8444e469a..3365148757cd845d12247d981877f5fb5f37515e 100644 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.less +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.less @@ -26,72 +26,11 @@ margin-bottom: 18px; } -/* 高发时段与统计卡片区域 */ +/* 统计卡片区域 */ .topSection { display: flex; gap: 15px; - margin: 0 16px 22px 15px; -} - -.topSection_thinLayout { - margin: 0 16px 15px 15px; -} - -/* 统计卡片样式 */ -.statsCards { - display: flex; - flex: 1; - gap: 16px; -} - -.statsCard { - flex: 1; - background-color: rgba(26, 40, 69, 0.7); - border-radius: 8px; - padding: 16px; - position: relative; - height: 120px; - display: flex; - flex-direction: column; - justify-content: center; -} - -.statsValue { - font-family: 'D-DIN'; - font-size: 32px; - font-weight: 600; - line-height: 1.2; -} - -.statsValueGroup { - display: flex; - flex-direction: column; - gap: 4px; -} - -.statsUnit { - font-size: 16px; - font-weight: normal; - margin-left: 4px; - color: #BCCEE9; -} - -.statsLabel { - font-size: 16px; - color: #BCCEE9; - margin-top: 4px; -} - -.statsIcon { - position: absolute; - right: 16px; - top: 16px; - width: 40px; - height: 40px; - border-radius: 20px; - display: flex; - align-items: center; - justify-content: center; + margin: 0 16px 14px 15px; } /* 中间内容样式 */ @@ -99,95 +38,10 @@ display: flex; gap: 16px; // margin-bottom: 27px; - margin: 0 16px 27px 15px; + margin: 0 16px 15px 15px; height: 224px; } -.middleContent_thinLayout { - margin: 0 16px 15px 15px; - height: 311px; -} - -// .sourceSection, -// .trendSection { -// flex: 1; -// background-color: rgba(26, 40, 69, 0.7); -// border-radius: 8px; -// height: 224px; -// } - -.sourceContent { - display: flex; - height: calc(100% - 52px); -} - -.pieChartContainer { - flex: 1; - height: 100%; - display: flex; - align-items: center; - justify-content: center; -} - -.sourceList { - width: 280px; - display: flex; - flex-direction: column; - justify-content: center; - gap: 16px; - padding-right: 16px; -} - -.sourceItem { - display: flex; - align-items: center; - gap: 8px; -} - -.sourceDot { - width: 8px; - height: 8px; - border-radius: 4px; -} - -.sourceType { - color: #BCCEE9; - font-size: 14px; - flex: 1; -} - -.sourceCount { - color: #BCCEE9; - font-size: 14px; - width: 80px; - text-align: right; -} - -.sourcePercentage { - color: #BCCEE9; - font-size: 14px; - width: 60px; - text-align: right; -} - -.trendContent { - height: calc(100% - 52px); - position: relative; -} - -.trendChart { - height: 100%; - width: 100%; -} - -.unitLabel { - position: absolute; - top: 0; - right: 0; - color: #BCCEE9; - font-size: 12px; -} - /* 底部内容样式 */ .bottomContent { display: flex; @@ -196,54 +50,3 @@ margin: 0 16px 0 15px; height: 380px; } - -.bottomContent_thinLayout { - // height: 311px; - max-height: 311px; -} - -.completionRateSection, -.highFrequencySection { - flex: 1; - background-color: rgba(26, 40, 69, 0.7); - border-radius: 8px; - padding: 16px; - height: 300px; -} - -.areaBarContainer { - display: flex; - flex-direction: column; - gap: 16px; - margin-top: 16px; -} - -.areaBar { - display: flex; - flex-direction: column; - gap: 4px; -} - -.areaName { - color: #FFFFFF; - font-size: 14px; -} - -.areaValue { - color: #23EBE2; - font-size: 14px; - text-align: right; -} - -.progressBarContainer { - height: 10px; - background-color: rgba(35, 235, 226, 0.1); - border-radius: 5px; - overflow: hidden; -} - -.progressBar { - height: 100%; - background: linear-gradient(to right, #31C6FA, #23EBE2); - border-radius: 5px; -} \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.tsx index a96eb1c09423934067f6bf6ef8be4543266900d1..0b3cb80bf616240776c206a5b2b35483f514824c 100644 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.tsx +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/components/RightContent/index.tsx @@ -4,8 +4,11 @@ import PanelTitle from '@/pages/Home_v_2504/components/common/PanelTitle'; import DateSelector from '@/components/V2504/DateSelector'; import styles from './index.less' -import MiddleContent from './MiddleContent'; - +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; +import StatisticsCards from './StatisticsCards'; +import CaseTrend from './CaseTrend'; +import HighFrequencyType from './HighFrequencyType'; +import CaseHandlingQuantity from './CaseHandlingQuantity'; interface Props { // 数据类型键名,用于获取正确的dataType @@ -16,6 +19,8 @@ interface Props { useHighFrequencyType?: boolean; // 是否使用瘦脸组件 isThinLayout?: boolean; + // 页面ID,用于区分不同页面的时间设置 + pageId?: string; } export default function RightContent({ @@ -23,14 +28,15 @@ export default function RightContent({ title = '市区协同', useHighFrequencyType = false, isThinLayout = false, + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_COORDINATION, }: Props) { - // 处理日期变化 - const handleDateChange = useCallback((params: { type: string; startTime: string; endTime: string }) => { - console.log('Date changed: RightContent!!', params); - - }, []); + // 处理日期变化 + const handleDateChange = useCallback((params: { type: string; startTime: string; endTime: string }) => { + console.log('Date changed: RightContent!!', params); + + }, []); return (
@@ -41,20 +47,25 @@ export default function RightContent({ onChange={handleDateChange} defaultType="lastMonth" panelType="right" - pageId="lawEnforcementCoordination" + pageId={pageId} timeOptions={['lastMonth', 'year', 'range']} // useDefaultTypeFirst={true} />
+
- +
- + +
) diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/index.tsx index d0a695d079aae2feed3c467ec960b0a0c4f2e586..5bc86e788a7d43f618a6c967c0fe9719112e7d5b 100644 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/index.tsx +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementCoordination/index.tsx @@ -21,7 +21,7 @@ const LawEnforcementCoordination: React.FC = ({ return ( { + // 默认所有区域 + 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 ''; +}; + +const CaseHandlingQuantity: React.FC = ({ + dateType, + dateRange, + isThinLayout = false, + dataTypeKey = '行政处罚', + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_PUNISHMENT, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 当前选中的区域类型 + const [currentTab, setCurrentTab] = useState('all'); + const currentTabRef = useLatestValue(currentTab); + + // 办案数量数据 + 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'; // 默认月视图 + } + }, []); + + // 处理Tab切换 + const handleTabChange = (tab: string) => { + setCurrentTab(tab as AreaType); + }; + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理办案数量API调用 + const highFrequencyApi = usePageAwareApi({ + 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; + } + + let isUsingMock = true; + const defaultPercentage = isUsingMock ? 99 : 0; + const defaultValue = isUsingMock ? 200 : 0; + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name, + percentage: parseFloat(item.percent) || defaultPercentage, + count: parseInt(item.value) || defaultValue + })); + + console.log('办案数量数据成功:'); + setData(formattedData); + }, + onError: (error) => { + console.error('获取办案数量数据出错:', error); + setData([]); + }, + apiName: '办案数量', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + pageId: pageId, // 传入页面ID用于页面感知 + }); + + // 在地图状态变化和Tab变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载办案数量数据'); + return; + } + + // 调用API - 现在usePageAwareApi内部会处理参数比较和页面状态 + highFrequencyApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, currentTab, buildApiParams, highFrequencyApi]); + + return ( +
+ +
+ +
+
+ ); +}; + +export default CaseHandlingQuantity; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/CaseSource/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/CaseSource/index.less new file mode 100644 index 0000000000000000000000000000000000000000..a2325df1db8b530694ef3a3104fb8620869ed904 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/CaseSource/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 224px; + 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: 10px 20px 0 30px; +} + +// .contentThin{ +// padding: 4px 18px 0 18px; +// } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/CaseSource/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/CaseSource/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3fdf726b504861f167591440d95a7712802e3c0b --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/CaseSource/index.tsx @@ -0,0 +1,191 @@ +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 { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +interface ProgramTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; + pageId?: string; +} + +const ProgramType: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '行政处罚', + isThinLayout = false, + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_PUNISHMENT, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(49, 198, 250)', 'rgb(255, 227, 53)', 'rgb(71, 223, 155)', 'rgb(170, 145, 255)', 'rgb(97, 141, 255)', 'rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)']; + + // 转换日期类型为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; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理问题来源API调用 + const sourceSystemRankApi = usePageAwareApi({ + apiFunction: async (params: any) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data: any) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: '市城运平台', value: 1625, percent: '32.53' }, + { name: '12345市民投诉', value: 1400, percent: '30.53' }, + { name: '数字城管巡查上报', value: 1322, percent: '20.8' }, + { name: '青羊区', value: 186, percent: '5.6' }, + { name: '双流区', value: 152, percent: '4.9' }, + ]; + console.log('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 转换接口返回的数据格式为图表需要的格式 + 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: any) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + enableDebug: false, + pageId: pageId, // 添加页面ID以启用页面感知 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,暂不加载问题来源数据'); + return; + } + + console.log(`加载${pageId}页面-案件来源 数据,参数:`, params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, buildApiParams, sourceSystemRankApi, pageId]); + + return ( +
+ +
+ +
+
+ ); +}; + +export default ProgramType; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/HighFrequencyType/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/HighFrequencyType/index.less new file mode 100644 index 0000000000000000000000000000000000000000..bbf7d303133a6877539c9ef9461e3b300df18e67 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/HighFrequencyType/index.less @@ -0,0 +1,17 @@ +.container { + width: 530px; + // height: 380px; + height: 100%; + 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/LawEnforcementPunishment/components/RightContent/HighFrequencyType/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/HighFrequencyType/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..31b8a67eee4212804b07ec6277c545ebcc53bfad --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/HighFrequencyType/index.tsx @@ -0,0 +1,229 @@ +import React, { useState, useEffect, useCallback, useRef } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import AreaBarList, { AreaBarItem } from '@/components/V2504/AreaBarList'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getDistrictHighFrequencyArea } from '@/services/CityProblem'; +import { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +// 类型定义 +export interface HighFrequencyTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + pageId?: string; +} + +// 区域类型定义 +export type AreaType = 'all' | 'urban' | 'central' | 'county'; + +// 区域级别定义 +export enum RegionLevelEnum { + CITY = '1', // 市级 + DISTRICT = '2', // 区县级 + STREET = '3', // 街道级 + GRID = '4', // 网格级 +} + +// 区域编码生成函数 +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 ''; +}; + +const HighFrequencyType: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '行政处罚', + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_PUNISHMENT, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 当前选中的区域类型 + const [currentTab, setCurrentTab] = useState('all'); + const currentTabRef = useLatestValue(currentTab); + + // 高发区域数据 + 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'; // 默认月视图 + } + }, []); + + // 处理Tab切换 + const handleTabChange = (tab: string) => { + setCurrentTab(tab as AreaType); + }; + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理高发区域API调用 + const highFrequencyApi = usePageAwareApi({ + 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; + } + + let isUsingMock = true; + const defaultPercentage = isUsingMock ? 99 : 0; + const defaultValue = isUsingMock ? 200 : 0; + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + name: item.name, + percentage: parseFloat(item.percent) || defaultPercentage, + count: parseInt(item.value) || defaultValue + })); + + console.log('高发区域数据成功:'); + setData(formattedData); + }, + onError: (error) => { + console.error('获取高发区域数据出错:', error); + setData([]); + }, + apiName: '高发类型', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + pageId: pageId, // 传入页面ID用于页面感知 + }); + + // 在地图状态变化和Tab变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,不加载高发类型数据'); + return; + } + + // 调用API - 现在usePageAwareApi内部会处理参数比较和页面状态 + highFrequencyApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, currentTab, buildApiParams, highFrequencyApi]); + + return ( +
+ +
+ +
+
+ ); +}; + +export default HighFrequencyType; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/ProgramType/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/ProgramType/index.less new file mode 100644 index 0000000000000000000000000000000000000000..bc5b088a0c56d02be0eb31e4064fa07d9b4a56b7 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/ProgramType/index.less @@ -0,0 +1,20 @@ +.container { + width: 530px; + height: 196px; + 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: 20px 20px 0 50px; +} + +// .contentThin{ +// padding: 4px 18px 0 18px; +// } \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/ProgramType/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/ProgramType/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bd22115793bb84453273525139d28b1b5a40ff93 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/ProgramType/index.tsx @@ -0,0 +1,201 @@ +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 { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import classNames from 'classnames'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +interface ProgramTypeProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; + pageId?: string; +} + +const ProgramType: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '行政处罚', + isThinLayout = false, + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_PUNISHMENT, +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 统计数据 + const [data, setData] = useState([]); + + // 图表颜色 + const colors = ['rgb(71, 223, 155)', 'rgb(97, 141, 255)', 'rgb(53, 193, 247)', 'rgb(152, 141, 252)', 'rgb(199, 195, 89)']; + + // 转换日期类型为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; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理问题来源API调用 + const sourceSystemRankApi = usePageAwareApi({ + apiFunction: async (params: any) => { + console.log('发起问题来源请求,参数:', params); + const response = await getSourceSystemRank(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题来源数据失败'); + }, + onSuccess: (data: any) => { + if (!data || !Array.isArray(data) || data.length === 0) { + let useMockData = true; + if (useMockData) { + data = [ + { name: '普通程序', value: 456, percent: '97.2' }, + { name: '简易程序', value: 400, percent: '83.5' }, + { name: '快速程序', value: 322, percent: '70.8' }, + // { 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('使用模拟问题来源数据'); + }else{ + setData([]); + return; + } + } + + // 转换接口返回的数据格式为图表需要的格式 + 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: any) => { + console.error('获取问题来源数据出错:', error); + setData([]); + }, + apiName: '问题来源', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + enableDebug: false, + pageId: pageId, // 添加页面ID以启用页面感知 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,暂不加载问题来源数据'); + return; + } + + console.log(`加载${pageId}页面-程序类型数据,参数:`, params); + sourceSystemRankApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, buildApiParams, sourceSystemRankApi, pageId]); + + return ( +
+ +
+ +
+
+ ); +}; + +export default ProgramType; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/PunishmentTrend/index.less b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/PunishmentTrend/index.less new file mode 100644 index 0000000000000000000000000000000000000000..7b68a14d5360e3b71e187f8e2ce89df35ffef2e0 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/PunishmentTrend/index.less @@ -0,0 +1,12 @@ +.container { + width: 530px; + height: 224px; + background: linear-gradient(180deg, 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); +} + +.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/LawEnforcementPunishment/components/RightContent/PunishmentTrend/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/PunishmentTrend/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..dc60d0aaf4c1647b4d894c20a4e1ff8fc97150f9 --- /dev/null +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/PunishmentTrend/index.tsx @@ -0,0 +1,306 @@ +import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'; +import ModuleTitleWithTabs from '@/pages/Home_v_2504/components/common/ModuleTitleWithTabs'; +import SmoothLineChart from '@/components/V2504/SmoothLineChart'; +import styles from './index.less'; +import { useDataType, useMapState } from '@/pages/Home_v_2504/components/MapStateContext'; +import { getEventTrends } from '@/services/CityProblem'; +import { formatDateTime } from '@/pages/Home_v_2504/hooks/useApiControl'; +import useLatestValue from '@/pages/Home_v_2504/hooks/useLatestValue'; +import usePageAwareApi from '@/pages/Home_v_2504/hooks/usePageAwareApi'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; + +// 类型定义 +interface PunishmentTrendProps { + dateType?: string; + dateRange?: { startTime: string; endTime: string }; + dataTypeKey?: string; + isThinLayout?: boolean; + pageId?: string; // 新增页面ID参数 +} + +const PunishmentTrend: React.FC = ({ + dateType, + dateRange, + dataTypeKey = '行政处罚', + isThinLayout = false, + pageId = INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_PUNISHMENT, // 默认为lawEnforcementPunishment +}) => { + // 地图状态 + const { mapState } = useMapState(); + const mapStateRef = useLatestValue(mapState); + + // 图表数据 + const [data, setData] = useState<{ time: string; value: number }[]>([]); + + // 转换日期类型为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'; // 默认月视图 + } + }, []); + + // 转换时间格式 - 参考LeftContent中的translateTrendTime函数 + const translateTrendTime = useCallback((inputDate: string | number) => { + if (typeof inputDate === 'string') { + // 处理类似'2025-11'的格式 + if (inputDate.includes('-') && inputDate.length === 7) { + const month = parseInt(inputDate.substring(5, 7)); + return `${month}月`; + } + // 处理类似'20250425'的格式 + // if (inputDate.length === 8) { + // const month = parseInt(inputDate.substring(4, 6)); + // const day = parseInt(inputDate.substring(6, 8)); + // return `${month}月${day}日`; + // } + // 处理YYYY-MM-DD格式 + if (inputDate.includes('-') && inputDate.length === 10) { + const dateParts = inputDate.split('-'); + if (dateParts.length >= 3) { + const month = parseInt(dateParts[1]); + const day = parseInt(dateParts[2]); + return `${month}月${day}日`; + } + } + // 处理类似"03"的格式 + if (inputDate.length === 2) { + if (inputDate === '23') { + return '23:59:59'; + } + return `${inputDate.padStart(2, '0')}:00:00`; + } + // console.log('inputDate:', inputDate); + return inputDate.substring(0, 10); + } + // 处理number类型 + if (typeof inputDate === 'number') { + if (inputDate === 23) { + return '23:59:59'; + } + return `${inputDate.toString().padStart(2, '0')}:00`; + } + return inputDate; + }, []); + + // 构建API请求参数 + const buildApiParams = useCallback(() => { + const currentMapState = mapStateRef.current; + + // 如果没有必要的时间参数,返回null表示不应该发起请求 + if (!currentMapState.rightPanelTime?.startTime || !currentMapState.rightPanelTime?.endTime) { + return null; + } + + // 获取当前页面的时间设置 + const pageTimeSettings = currentMapState.pageTimeSettings?.[pageId]; + if (!pageTimeSettings) { + console.log(`缺少${pageId}页面的时间设置,使用全局设置`); + } + + // 使用页面级别的时间设置,如果存在的话 + const rightPanelTime = pageTimeSettings?.rightPanelTime || currentMapState.rightPanelTime; + + // 使用当前时间类型,如果不存在则使用props或默认值 + const effectiveType = rightPanelTime.type || dateType || 'month'; + + // 基础参数对象 + const params: any = { + type: translateDateType(effectiveType) + }; + + // 处理日期参数 + if (effectiveType === 'range') { + params.customizeStart = formatDateTime(rightPanelTime.startTime); + params.customizeEnd = formatDateTime(rightPanelTime.endTime, true); + } else { + // 年、月、日视图使用time参数 + params.time = formatDateTime(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, pageId]); + + // 使用usePageAwareApi管理问题趋势API调用 + const eventTrendsApi = usePageAwareApi({ + apiFunction: async (params: any) => { + console.log('发起问题趋势请求,参数:', params); + const response = await getEventTrends(params); + + if (response.code === 200 && response.data) { + return response.data; + } + + throw new Error('获取问题趋势数据失败'); + }, + onSuccess: (data: any) => { + if (!data || !Array.isArray(data)) { + setData([]); + return; + } + console.log('onSuccess:'); + + let isUseMockData = true; + if (isUseMockData) { + setData(mockData); + return; + } + + const isSupplementData = false; + // 如果是月数据,补充到月底 '2025-05-06' + if (data[0].name.includes('-') && data[0].name.length === 10 && isSupplementData) { + // 获取当前日期 + const today = new Date(); + const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 1); + // console.log('lastDay:', lastDay); + + // 生成完整日期范围 + const fullData = [...data]; // 先复制已有数据 + + // 从明天开始补充数据 + for (let d = new Date(today); d <= lastDay; d.setDate(d.getDate() + 1)) { + // 跳过今天及之前的日期 + if (d <= today) continue; + + const dateStr = d.toISOString().slice(0, 10).replace(/-/g, '-'); + fullData.push({ + name: dateStr, + value: '0' + }); + } + data = fullData; + // console.log('补充到月底的数据:', data); + } + + // 如果是小时数据,补充到23点 + if (data[0].name.length === 2 && isSupplementData) { + // 获取当前小时 + const currentHour = new Date().getHours(); + // 生成完整小时范围 + const fullData = [...data]; // 先复制已有数据 + + // 从下一小时开始补充数据 + for (let h = currentHour + 1; h <= 23; h++) { + const hourStr = h.toString().padStart(2, '0'); + fullData.push({ + name: hourStr, + value: '0' + }); + } + data = fullData; + } + + // 转换接口返回的数据格式为图表需要的格式 + const formattedData = data.map((item: any) => ({ + time: translateTrendTime(item.name), + value: parseInt(item.value) || 0 + })); + + console.log('问题趋势数据成功:'); + setData(formattedData); + }, + onError: (error: any) => { + console.error('获取问题趋势数据出错:', error); + // 出错时使用空数据 + setData([]); + }, + apiName: '问题趋势', + debounceTime: 300, + cacheTime: 5000, // 缓存5秒,避免频繁刷新时重复请求 + enableDebug: false, + pageId: pageId, // 添加页面ID以启用页面感知 + }); + + // 在地图状态变化时加载数据 + useEffect(() => { + const params = buildApiParams(); + + // 如果没有必要的参数,不发送请求 + if (!params) { + console.log('缺少必要的日期参数,暂不加载问题趋势数据'); + return; + } + + console.log(`加载${pageId}页面问题趋势数据,参数:`, params); + eventTrendsApi.callApi(params); + + }, [mapState.regionCode, mapState.rightPanelTime, mapState.pageTimeSettings, buildApiParams, eventTrendsApi, pageId]); + + const chartStyle = useMemo(() => ({ + height: isThinLayout ? '278px' : '178px', + width: '100%' + }), [isThinLayout]); + + + // Mock data for the chart + const mockData: { time: string; value: number }[] = [ + { 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: 310 }, + { time: '11:00:00', value: 425 }, + { time: '12:00:00', value: 330 }, + { time: '13:00:00', value: 320 }, + { time: '14:00:00', value: 265 }, + { time: '15:00:00', value: 255 }, + { time: '16:00:00', value: 240 }, + { time: '17:00:00', value: 235 }, + { 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 }, + ]; + + + return ( +
+ +
+ +
+
+ ); +}; + +export default PunishmentTrend; \ No newline at end of file diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/index.tsx index 2efdeda40da890cacfef95be45495d1251feb0bb..1b3f882f068cd19ce6b1bda5cdeaab701bae4c48 100644 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/index.tsx +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/components/RightContent/index.tsx @@ -4,8 +4,14 @@ import PanelTitle from '@/pages/Home_v_2504/components/common/PanelTitle'; import OverallSituation from './OverallSituation'; import DateSelector from '@/components/V2504/DateSelector'; +import ProgramType from './ProgramType'; +import CaseSource from './CaseSource'; import styles from './index.less' +import PunishmentTrend from './PunishmentTrend'; +import HighFrequencyType from './HighFrequencyType'; +import { INDUSTRY_PAGE_IDS } from '@/constants/dataTypes'; +import CaseHandlingQuantity from './CaseHandlingQuantity'; interface Props { // 数据类型键名,用于获取正确的dataType @@ -41,19 +47,23 @@ export default function RightContent({ onChange={handleDateChange} defaultType="lastMonth" panelType="right" - pageId="lawEnforcementPunishment" + pageId = {INDUSTRY_PAGE_IDS.LAW_ENFORCEMENT_PUNISHMENT} timeOptions={['lastMonth', 'year', 'range']} // useDefaultTypeFirst={true} />
+
+ +
- + +
) diff --git a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/index.tsx b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/index.tsx index cc1a99b23a58842ed4230c2880ea1616f2f8f407..18edbec90ebedc9c03cffe1ef90e4accd504a19c 100644 --- a/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/index.tsx +++ b/src/pages/Home_v_2504/components/SubPages/LawEnforcementPunishment/index.tsx @@ -18,7 +18,7 @@ const LawEnforcementPunishment: React.FC = ({ vis return ( = ({ data={data} unitText="单位:件" lineColor="rgb(136, 238, 248)" - lineColorStop1="rgba(136, 238, 248, 0)" - lineColorStop2="rgba(136, 238, 248, 0.36)" + lineColorStop1="rgba(136, 238, 248, 0.36)" + lineColorStop2="rgba(136, 238, 248, 0)" style={chartStyle} />