From 3f488c59f2d3301444969ba2bd39788cd3bbb8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=E5=85=88=E7=94=9F?= <1211120248@qq.com> Date: Wed, 12 Aug 2026 23:15:24 +0800 Subject: [PATCH] feat(ecology): normalize national park data flow --- src/config/layers.js | 10 +-- src/services/ecologicalProtectionApi.js | 48 ++++++++---- src/views/ecologicalProtection/data.js | 73 +++++-------------- src/views/ecologicalProtection/index.vue | 47 ++++++++---- .../components/FeatureInfoPanel.vue | 23 +++++- 5 files changed, 107 insertions(+), 94 deletions(-) diff --git a/src/config/layers.js b/src/config/layers.js index 1e2a8ba..37a2b08 100644 --- a/src/config/layers.js +++ b/src/config/layers.js @@ -475,10 +475,8 @@ export const ecologicalProtectionLayers = { { key: "national-park-zoning", name: "国家公园分区", - sourceType: "wkt-api", - apiUrl: "/openApi/gjgy/gjgy_area", - clipToHongyuanBoundary: true, - clipToLayerBounds: false, + layerName: "ne:resource_national_park_boundary_render", + sourceType: "wfs", opacity: 0.9, mapView: { targetLngLat: [102.88, 33.15], @@ -492,7 +490,7 @@ export const ecologicalProtectionLayers = { name: "核心保护区", fillColor: NATIONAL_PARK_ZONING_COLORS.core.fillColor, strokeColor: NATIONAL_PARK_ZONING_COLORS.core.strokeColor, - match: { field: "type", value: "核心保护区" }, + match: { field: "zone_type", value: "核心保护区" }, selectable: false, }, { @@ -500,7 +498,7 @@ export const ecologicalProtectionLayers = { name: "一般控制区", fillColor: NATIONAL_PARK_ZONING_COLORS.general.fillColor, strokeColor: NATIONAL_PARK_ZONING_COLORS.general.strokeColor, - match: { field: "type", value: "一般控制区" }, + match: { field: "zone_type", value: "一般控制区" }, selectable: false, }, ], diff --git a/src/services/ecologicalProtectionApi.js b/src/services/ecologicalProtectionApi.js index e7f816f..31ece36 100644 --- a/src/services/ecologicalProtectionApi.js +++ b/src/services/ecologicalProtectionApi.js @@ -42,31 +42,49 @@ async function getEcologicalDirectStats(path, featureName) { return stats } -const NATIONAL_PARK_JSON_FIELDS = [ +const NATIONAL_PARK_ROW_SECTIONS = [ "topRows", "coreRows", "townRows", - "townResourceRows", - "townProductivityRows", - "townYakRows", - "townHouseholdRows", - "townJobRows", - "zoningRows", - "balanceGaugeRows", "villageRows", ] +const NATIONAL_PARK_PANEL_KEYS = [ + "townResource", + "townProductivity", + "townYak", + "townHousehold", + "townJob", + "zoning", + "balance", +] + export async function getNationalParkStats() { const response = await requestJson( - `${OPEN_API_BASE}/screen2/ecologicalProtection/nationalPark`, + `${OPEN_API_BASE}/screen2/ecology/national-park`, { method: "GET", timeout: 30000 }, ) - const data = normalizeResponseData(response) - const stats = Array.isArray(data) ? data[0] || {} : data || {} - return NATIONAL_PARK_JSON_FIELDS.reduce((result, key) => { - result[key] = parseJsonbRows(stats[key]) - return result - }, { ...stats }) + const payload = normalizeResponseData(response) + const stats = payload || {} + + if (Array.isArray(stats) || !stats || typeof stats !== "object" || !["ready", "empty"].includes(stats.dataState)) { + throw new Error("国家公园接口返回的数据状态无效。") + } + NATIONAL_PARK_ROW_SECTIONS.forEach((key) => assertDirectRows(stats[key], `国家公园 ${key}`)) + if (!stats.panels || typeof stats.panels !== "object") { + throw new Error("国家公园接口未返回完整展示面板。") + } + NATIONAL_PARK_PANEL_KEYS.forEach((key) => assertDirectRows(stats.panels[key], `国家公园 ${key} 面板`)) + return stats +} + +function assertDirectRows(section, label) { + if (!section || typeof section !== "object" || !Array.isArray(section.rows) || !Number.isInteger(section.count)) { + throw new Error(`${label}未返回合法的 rows/count 展示模型。`) + } + if (section.count !== section.rows.length) { + throw new Error(`${label}的 count 与 rows 数量不一致。`) + } } const RESTORATION_JSON_FIELDS = [ diff --git a/src/views/ecologicalProtection/data.js b/src/views/ecologicalProtection/data.js index 921e69f..1889810 100644 --- a/src/views/ecologicalProtection/data.js +++ b/src/views/ecologicalProtection/data.js @@ -1,9 +1,7 @@ -import { NATIONAL_PARK_ZONING_COLORS } from "@/config/layers" import { ecologicalProtectionMenu } from "@/config/ecologicalProtection" export { ecologicalProtectionMenu } -const sumBy = (rows, field) => rows.reduce((sum, item) => sum + Number(item[field] || 0), 0) const round = (value, digits = 2) => Number(Number(value || 0).toFixed(digits)) const ecologicalDirectPanelDefinitions = { @@ -57,60 +55,27 @@ function normalizeEcologicalRows(value = []) { })) } +function getNationalParkRows(stats, key) { + return stats?.[key]?.rows || [] +} + +function getNationalParkPanelRows(stats, key) { + return stats?.panels?.[key]?.rows || [] +} + export function getNationalParkTopStats(stats = {}) { - return normalizeEcologicalRows(stats.topRows).map((item, index) => ({ - icon: item.icon || (index % 2 === 0 ? "xiaoshoujine" : "zongxiaoliang"), - en: "", - ...item, - })) + return getNationalParkRows(stats, "topRows") } export function getNationalParkCoreRows(stats = {}) { - return normalizeEcologicalRows(stats.coreRows) + return getNationalParkRows(stats, "coreRows") } export function getNationalParkTownRows(stats = {}) { - return normalizeEcologicalRows(stats.townRows) -} - -function withNationalParkPercentExtra(rows = []) { - const total = sumBy(rows, "value") - return rows.map((item) => ({ - ...item, - extra: item.extra || `占比 ${round((Number(item.value || 0) / Math.max(total, 1)) * 100, 1)}%`, - })) + return getNationalParkRows(stats, "townRows") } export function buildNationalParkPanels(stats = {}) { - const townRows = getNationalParkTownRows(stats) - const townByName = new Map(townRows.map((item) => [item.name, item])) - const areaRows = normalizeEcologicalRows(stats.townResourceRows) - const productivityRows = normalizeEcologicalRows(stats.townProductivityRows) - const yakRows = withNationalParkPercentExtra(normalizeEcologicalRows(stats.townYakRows)) - const zoningRows = withNationalParkPercentExtra( - normalizeEcologicalRows(stats.zoningRows).map((item) => ({ - ...item, - color: item.name === "核心保护区" - ? NATIONAL_PARK_ZONING_COLORS.core.fillColor - : item.name === "一般控制区" - ? NATIONAL_PARK_ZONING_COLORS.general.fillColor - : item.color, - })), - ) - const householdRows = normalizeEcologicalRows(stats.townHouseholdRows).map((item) => ({ - ...item, - extra: `公益岗位 ${Number(item.ecologyJobs || 0)}户`, - })) - const jobColors = { - 麦洼乡: "#24f6c4", - 瓦切镇: "#32dcff", - 色地镇: "#8bf7ff", - } - const jobRows = normalizeEcologicalRows(stats.townJobRows).map((item) => ({ - ...item, - color: jobColors[item.name], - extra: `牧户 ${Number(townByName.get(item.name)?.householdCount || 0)}户`, - })) return { left: [ { @@ -125,7 +90,7 @@ export function buildNationalParkPanels(stats = {}) { { key: "grassland", name: "草地面积", color: "#24f6c4" }, { key: "wetland", name: "湿地面积", color: "#8bf7ff" }, ], - rows: areaRows, + rows: getNationalParkPanelRows(stats, "townResource"), }, { key: "park-town-productivity", @@ -135,21 +100,21 @@ export function buildNationalParkPanels(stats = {}) { labelMode: "horizontal", showValues: true, unit: "万吨", - rows: productivityRows, + rows: getNationalParkPanelRows(stats, "townProductivity"), }, { key: "park-town-yak", title: "乡镇牦牛数量", type: "bar", variant: "parkBar", - rows: yakRows, + rows: getNationalParkPanelRows(stats, "townYak"), }, { key: "park-town-balance", title: "草畜平衡超载率", type: "balanceGaugeGrid", limit: 1, - rows: normalizeEcologicalRows(stats.balanceGaugeRows), + rows: getNationalParkPanelRows(stats, "balance"), }, ], right: [ @@ -157,20 +122,20 @@ export function buildNationalParkPanels(stats = {}) { key: "park-zoning-structure", title: "红原管控区结构", type: "donut", - rows: zoningRows, + rows: getNationalParkPanelRows(stats, "zoning"), }, { key: "park-town-household", title: "牧户分布", type: "split", - rows: householdRows, + rows: getNationalParkPanelRows(stats, "townHousehold"), }, { key: "park-town-ecology-job", title: "公益岗位分布", type: "column", variant: "plain", - rows: jobRows, + rows: getNationalParkPanelRows(stats, "townJob"), }, ], } @@ -420,7 +385,7 @@ export function getEcologicalMapRanking(viewKey, stats = {}) { unit: "万亩", rows: getNationalParkTownRows(stats).map((item) => ({ name: item.name, - value: round(item.protectedAreaWanMu, 2), + value: item.value, unit: "万亩", metricLabel: "划定面积", })), diff --git a/src/views/ecologicalProtection/index.vue b/src/views/ecologicalProtection/index.vue index 4a32d85..7b3c0bd 100644 --- a/src/views/ecologicalProtection/index.vue +++ b/src/views/ecologicalProtection/index.vue @@ -15,13 +15,13 @@