From f0dd3b830ced9d16f27afd83b9ced811fc22ea1b Mon Sep 17 00:00:00 2001 From: wintsa <770775984@qq.com> Date: Mon, 17 Aug 2026 11:18:34 +0800 Subject: [PATCH] 1 --- src/App.tsx | 103 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 5d14199..f0a5d5d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,7 @@ import { } from 'ag-grid-community'; import type { AgCartesianChartOptions } from 'ag-charts-community'; import { ModuleRegistry } from 'ag-charts-community'; -import { Building2, CalendarRange, Construction, LayoutGrid, Library, LocateFixed, MapPinned, PanelRightClose, PanelRightOpen, Ruler, Waypoints } from 'lucide-react'; +import { Building2, CalendarRange, Construction, House, LayoutGrid, Library, LocateFixed, MapPinned, PanelRightClose, PanelRightOpen, Ruler, Waypoints } from 'lucide-react'; import { AnnotationsModule, ContextMenuModule, @@ -73,6 +73,7 @@ const filterOptions = [ { key: 'region', label: '省市区', icon: MapPinned }, { key: 'geoLocation', label: '自然地理区位', icon: LocateFixed }, { key: 'facilityType', label: '设施类别', icon: Building2 }, + { key: 'buildingNature', label: '建筑性质', icon: House }, { key: 'constructionStage', label: '建设阶段', icon: Construction }, { key: 'planningForm', label: '规划形式', icon: LayoutGrid }, { key: 'time', label: '时间', icon: CalendarRange }, @@ -127,6 +128,18 @@ const contentTreeConfigs = { }, } as const; +const buildingNatureBrowserConfig = { + conditionEndpoint: '/api/public/browser/condition/256', + dataEndpoint: '/api/public/browser/data/256', + treeid: '95504', + fieldid: '316390', + searchbrowserid: '36523', + browserParams: { + requestid: '', isshowsearchtab: '1', workflowid: '182028', wfid: '182028', billid: '-1815', + f_weaver_belongto_userid: '', f_weaver_belongto_usertype: '', wf_isagent: '', wf_beagenter: '', wfCreater: '', + }, +} as const; + const chartLineColors = ['#0078a8', '#d14d72', '#1f8f4d', '#d96f23', '#6b5cc8', '#0d7680', '#9a6b12', '#b24b38']; const defaultTemplateFilterNode = { id: '3', @@ -589,12 +602,16 @@ function isIndicatorTreeFilterKey(filterKey: FilterKey): filterKey is 'indicator return filterKey === 'indicatorTree'; } +function isBuildingNatureFilterKey(filterKey: FilterKey): filterKey is 'buildingNature' { + return filterKey === 'buildingNature'; +} + function isRangeFilterKey(filterKey: FilterKey): filterKey is RangeFilterKey { return filterKey === 'time' || filterKey === 'area'; } function isSingleSelectFilterKey(filterKey: FilterKey) { - return isTemplateFilterKey(filterKey) || isIndicatorTreeFilterKey(filterKey); + return isTemplateFilterKey(filterKey) || isIndicatorTreeFilterKey(filterKey) || isBuildingNatureFilterKey(filterKey); } function getDefaultTemplateFilterNodes(): SelectedFilterNode[] { @@ -756,6 +773,7 @@ function App() { region: false, geoLocation: false, facilityType: false, + buildingNature: false, constructionStage: false, planningForm: false, time: false, @@ -801,6 +819,7 @@ function App() { region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [], @@ -812,6 +831,7 @@ function App() { region: false, geoLocation: false, facilityType: false, + buildingNature: false, constructionStage: false, planningForm: false, time: false, @@ -823,6 +843,7 @@ function App() { region: null, geoLocation: null, facilityType: null, + buildingNature: null, constructionStage: null, planningForm: null, time: null, @@ -834,6 +855,7 @@ function App() { region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [], @@ -845,6 +867,7 @@ function App() { region: false, geoLocation: false, facilityType: false, + buildingNature: false, constructionStage: false, planningForm: false, time: false, @@ -856,6 +879,7 @@ function App() { region: null, geoLocation: null, facilityType: null, + buildingNature: null, constructionStage: null, planningForm: null, time: null, @@ -867,6 +891,7 @@ function App() { region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [], @@ -884,6 +909,7 @@ function App() { region: 0, geoLocation: 0, facilityType: 0, + buildingNature: 0, constructionStage: 0, planningForm: 0, time: 0, @@ -938,7 +964,10 @@ function App() { ); const indicatorSelectionLabel = appliedFilters.indicatorTree[0]?.label ?? defaultIndicatorTreeNodes[0]?.label ?? ''; const activeFilterCount = Object.entries(appliedFilters).reduce((total, [key, nodes]) => ( - key === 'templateLibrary' && isDefaultTemplateSelection(nodes) ? total : total + nodes.length + (key === 'templateLibrary' && isDefaultTemplateSelection(nodes)) + || (key === 'indicatorTree' && isDefaultIndicatorTreeSelection(nodes, filterTreeByKey.indicatorTree)) + ? total + : total + nodes.length ), 0); const chartEmptyText = selectedContentNodes.length === 0 ? '请选择右侧分类项' @@ -1197,6 +1226,15 @@ function App() { () => new Set(draftFilterNodes.map((node) => getFilterSelectionKey(node.filterKey, node.id))), [draftFilterNodes], ); + + useEffect(() => { + if (defaultIndicatorTreeNodes.length === 0) return; + setAppliedFilters((current) => { + if (current.indicatorTree.length > 0) return current; + return { ...current, indicatorTree: defaultIndicatorTreeNodes }; + }); + }, [defaultIndicatorTreeNodes]); + const appliedFilterPayload = useMemo( () => filterOptions .filter((option) => option.key !== 'time') @@ -1207,6 +1245,7 @@ function App() { .filter((filter) => filter.nodes.length > 0), [ appliedFilters.area, + appliedFilters.buildingNature, appliedFilters.constructionStage, appliedFilters.facilityType, appliedFilters.geoLocation, @@ -1265,6 +1304,28 @@ function App() { return normalizeTreeRows(rows); }; + const fetchBuildingNatureFilterTree = async (nodeId?: string, signal?: AbortSignal) => { + const treeParams = { + ...browserTreeDefaults, + ...buildingNatureBrowserConfig.browserParams, + treeid: buildingNatureBrowserConfig.treeid, + cube_treeid: buildingNatureBrowserConfig.treeid, + searchbrowserid: buildingNatureBrowserConfig.searchbrowserid, + fieldid: buildingNatureBrowserConfig.fieldid, + }; + const requestOptions: RequestInit = { credentials: 'include', signal, headers: { 'X-Requested-With': 'XMLHttpRequest' } }; + if (!nodeId) { + const conditionResponse = await fetch(`${buildingNatureBrowserConfig.conditionEndpoint}?${buildQuery(treeParams)}`, requestOptions); + if (!conditionResponse.ok) throw new Error(`建筑性质浏览条件加载失败:HTTP ${conditionResponse.status}`); + } + const dataParams = nodeId + ? { ...treeParams, type: '2', id: nodeId, isVirtual: '' } + : { ...treeParams, pageSize: '10', current: '1', min: '1', max: '10' }; + const response = await fetch(`${buildingNatureBrowserConfig.dataEndpoint}?${buildQuery(dataParams)}`, requestOptions); + if (!response.ok) throw new Error(`建筑性质浏览数据加载失败:HTTP ${response.status}`); + return normalizeTreeRows(pickArray(await response.json())); + }; + const normalizeBackendTree = (nodes: TreeNode[]): TreeNode[] => nodes.map((node) => ({ ...node, hasChildren: node.children.length > 0 || node.hasChildren, @@ -1378,6 +1439,12 @@ function App() { }; const loadFilterTree = async (filterKey: FilterKey, keyword?: string, signal?: AbortSignal) => { + if (isBuildingNatureFilterKey(filterKey)) { + const nodes = filterTreeByKey.buildingNature.length > 0 + ? filterTreeByKey.buildingNature + : await fetchBuildingNatureFilterTree(undefined, signal); + return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes; + } if (filterKey === 'region') { const nodes = await fetchRegionFilterTree(signal); return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes; @@ -1584,7 +1651,7 @@ function App() { return; } - if (isTemplateFilterKey(filterKey) || filterKey === 'indicatorTree') { + if (isTemplateFilterKey(filterKey) || filterKey === 'indicatorTree' || isBuildingNatureFilterKey(filterKey)) { filterSearchTimerRef.current = window.setTimeout(() => { setFilterSearchLoadingByKey((current) => ({ ...current, [filterKey]: true })); setFilterSearchErrorByKey((current) => ({ ...current, [filterKey]: null })); @@ -1641,10 +1708,12 @@ function App() { })), })); - if (node.loaded || !isContentFilterKey(filterModalKey)) return; + if (node.loaded || (!isContentFilterKey(filterModalKey) && !isBuildingNatureFilterKey(filterModalKey))) return; const currentFilterKey = filterModalKey; - const childRequest = fetchContentTree(currentFilterKey, nodeId); + const childRequest = isBuildingNatureFilterKey(currentFilterKey) + ? fetchBuildingNatureFilterTree(nodeId) + : fetchContentTree(currentFilterKey, nodeId); childRequest .then((children) => { setFilterTreeByKey((current) => ({ @@ -1737,22 +1806,18 @@ function App() { if (nextDraftNodes.length === 0) { nextDraftNodes = defaultIndicatorTreeNodes; } - if (isDefaultIndicatorTreeSelection(nextDraftNodes, filterTreeByKey.indicatorTree)) { - nextDraftNodes = []; - } } - const shouldReloadIndicatorTree = isTemplateFilterKey(filterModalKey) && !isSameFilterSelection(appliedFilters.templateLibrary, nextDraftNodes); setAppliedFilters((current) => { const nextFilters = { ...current, [filterModalKey]: nextDraftNodes, }; - if (shouldReloadIndicatorTree) { + if (isTemplateFilterKey(filterModalKey)) { nextFilters.indicatorTree = []; } return nextFilters; }); - if (shouldReloadIndicatorTree) { + if (isTemplateFilterKey(filterModalKey)) { resetIndicatorTreeState(); } setChartDataBySelection({}); @@ -1876,13 +1941,6 @@ function App() { }); }, [activeContentKey, treeByContent]); - useEffect(() => { - if (filterModalKey !== 'indicatorTree') return; - if (draftFilterNodes.length > 0) return; - if (defaultIndicatorTreeNodes.length === 0) return; - setDraftFilterNodes(defaultIndicatorTreeNodes); - }, [defaultIndicatorTreeNodes, draftFilterNodes.length, filterModalKey]); - useEffect(() => { const controller = new AbortController(); @@ -2430,16 +2488,13 @@ function App() { type="button" title="清空全部筛选" onClick={() => { - const shouldReloadIndicatorTree = !isDefaultTemplateSelection(appliedFilters.templateLibrary); - if (shouldReloadIndicatorTree) { - resetIndicatorTreeState(); - } setAppliedFilters({ templateLibrary: getDefaultTemplateFilterNodes(), - indicatorTree: [], + indicatorTree: defaultIndicatorTreeNodes, region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [],