diff --git a/src/config/layers.js b/src/config/layers.js index 72a8c43..1e2a8ba 100644 --- a/src/config/layers.js +++ b/src/config/layers.js @@ -429,7 +429,7 @@ export const ecologicalProtectionLayers = { { key: "natural-protected-area-boundary", name: "自然保护地", - layerName: "ne:t_natural_protected_area_hy", + layerName: "ne:resource_natural_protected_area_boundary", sourceType: "wfs", styles: "natural_protected_area_hy", opacity: 0.74, diff --git a/src/services/ecologicalProtectionApi.js b/src/services/ecologicalProtectionApi.js index c99a09a..e7f816f 100644 --- a/src/services/ecologicalProtectionApi.js +++ b/src/services/ecologicalProtectionApi.js @@ -2,7 +2,7 @@ import { normalizeResponseData, requestJson } from "./request" const OPEN_API_BASE = import.meta.env.VITE_OPEN_API_BASE || "/openApi" -const REDLINE_PANEL_KEYS = [ +const ECOLOGICAL_DIRECT_PANEL_KEYS = [ "grasslandDistribution", "wetlandDistribution", "woodlandDistribution", @@ -14,38 +14,34 @@ const REDLINE_PANEL_KEYS = [ ] export async function getEcologicalRedlineStats() { + return getEcologicalDirectStats("redline", "生态保护红线") +} + +export async function getNaturalProtectedAreaStats() { + return getEcologicalDirectStats("protected-area", "自然保护地") +} + +async function getEcologicalDirectStats(path, featureName) { const response = await requestJson( - `${OPEN_API_BASE}/screen2/ecology/redline`, - // The initial spatial overlay can populate PostGIS caches after a service - // restart; retain the page's explicit loading/error state while allowing - // the complete normalized result to arrive. + `${OPEN_API_BASE}/screen2/ecology/${path}`, { method: "GET", timeout: 30000 }, ) const payload = normalizeResponseData(response) const stats = Array.isArray(payload) ? payload[0] || {} : payload || {} if (!stats || typeof stats !== "object" || !["ready", "empty"].includes(stats.dataState)) { - throw new Error("生态保护红线接口返回的数据状态无效。") + throw new Error(`${featureName}接口返回的数据状态无效。`) } if (!Array.isArray(stats.topRows?.rows) || !stats.panels || typeof stats.panels !== "object") { - throw new Error("生态保护红线接口未返回完整展示模型。") + throw new Error(`${featureName}接口未返回完整展示模型。`) } - const invalidPanelKey = REDLINE_PANEL_KEYS.find((key) => !Array.isArray(stats.panels[key]?.rows)) + const invalidPanelKey = ECOLOGICAL_DIRECT_PANEL_KEYS.find((key) => !Array.isArray(stats.panels[key]?.rows)) if (invalidPanelKey) { - throw new Error(`生态保护红线接口缺少 ${invalidPanelKey} 面板展示数据。`) + throw new Error(`${featureName}接口缺少 ${invalidPanelKey} 面板展示数据。`) } return stats } -export async function getNaturalProtectedAreaStats() { - const response = await requestJson( - `${OPEN_API_BASE}/screen2/ecologicalProtection/naturalProtectedArea`, - { method: "GET", timeout: 30000 }, - ) - const data = normalizeResponseData(response) - return normalizeEcologicalScopeStats(Array.isArray(data) ? data[0] || {} : data || {}) -} - const NATIONAL_PARK_JSON_FIELDS = [ "topRows", "coreRows", @@ -127,46 +123,3 @@ function parseJsonbRows(value) { return [] } } - -const ECOLOGICAL_SCOPE_FIELD_MAP = { - scope_key: "scopeKey", - scope_name: "scopeName", - scope_area_wan_mu: "scopeAreaWanMu", - source_feature_count: "sourceFeatureCount", - grassland_area_wan_mu: "grasslandAreaWanMu", - wetland_area_wan_mu: "wetlandAreaWanMu", - woodland_area_wan_mu: "woodlandAreaWanMu", - grassland_fresh_yield_wan_ton: "grasslandFreshYieldWanTon", - wetland_fresh_yield_wan_ton: "wetlandFreshYieldWanTon", - grassland_mu_yield_jin: "grasslandMuYieldJin", - wetland_mu_yield_jin: "wetlandMuYieldJin", - grassland_vegetation_cover_percent: "grasslandVegetationCoverPercent", - grassland_patch_count: "grasslandPatchCount", - wetland_patch_count: "wetlandPatchCount", - woodland_patch_count: "woodlandPatchCount", - grassland_distribution: "grasslandDistribution", - wetland_distribution: "wetlandDistribution", - woodland_distribution: "woodlandDistribution", - grassland_productivity: "grasslandProductivity", - grassland_types: "grasslandTypes", - zoning_structure: "zoningStructure", - grassland_levels: "grasslandLevels", - vegetation_cover_bands: "vegetationCoverBands", - woodland_types: "woodlandTypes", - woodland_quality: "woodlandQuality", - area_method: "areaMethod", - area_unit: "areaUnit", - productivity_method: "productivityMethod", -} - -function normalizeEcologicalScopeStats(raw = {}) { - if (!raw || typeof raw !== "object") return {} - return Object.entries(raw).reduce((result, [key, value]) => { - result[key] = value - const normalizedKey = ECOLOGICAL_SCOPE_FIELD_MAP[key] - if (normalizedKey && result[normalizedKey] === undefined) { - result[normalizedKey] = value - } - return result - }, {}) -} diff --git a/src/views/ecologicalProtection/data.js b/src/views/ecologicalProtection/data.js index d1e9c65..921e69f 100644 --- a/src/views/ecologicalProtection/data.js +++ b/src/views/ecologicalProtection/data.js @@ -1,18 +1,12 @@ -import { hongyuanTownshipDisplayOrder } from "@/config/townshipBoundaries" import { NATIONAL_PARK_ZONING_COLORS } from "@/config/layers" import { ecologicalProtectionMenu } from "@/config/ecologicalProtection" export { ecologicalProtectionMenu } -const toWanMu = (mu) => Number((Number(mu || 0) / 10000).toFixed(2)) 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)) -// The legacy scope builder is retained solely for the natural-protected-area view. -// Ecological redline data is an API-owned ready-to-render model below. -export const ecologicalScopeViewKeys = ["natural-protected-area"] - -const ecologicalRedlinePanelDefinitions = { +const ecologicalDirectPanelDefinitions = { left: [ { key: "grasslandDistribution", title: "草地分布", type: "column", variant: "plain", labelMode: "horizontal", scrollable: false, span: 1 }, { key: "wetlandDistribution", title: "湿地面积", type: "rank", labelMode: "horizontal", scrollable: false, span: 1 }, @@ -27,9 +21,9 @@ const ecologicalRedlinePanelDefinitions = { ], } -export function buildEcologicalRedlinePanels(panels = {}) { +function buildEcologicalDirectPanels(panels = {}) { return Object.fromEntries( - Object.entries(ecologicalRedlinePanelDefinitions).map(([side, definitions]) => [ + Object.entries(ecologicalDirectPanelDefinitions).map(([side, definitions]) => [ side, definitions.map((definition) => ({ ...definition, @@ -40,180 +34,8 @@ export function buildEcologicalRedlinePanels(panels = {}) { ) } -function normalizeScopeRows(value = []) { - let rows = value - if (rows && typeof rows === "object" && !Array.isArray(rows) && "value" in rows) { - rows = rows.value - } - if (typeof rows === "string") { - try { - rows = JSON.parse(rows) - } catch { - rows = [] - } - } - return (Array.isArray(rows) ? rows : []).map((item, index) => ({ - key: item.key || `${item.name || "统计项"}-${index}`, - name: item.name || `统计项${index + 1}`, - value: round(item.value, 2), - unit: item.unit || "万亩", - color: item.color, - extra: item.extra || "", - icon: item.icon || "", - })) -} - -function scopeMetric(key, name, value, unit, extra = "") { - return { key, name, value: round(value, unit === "%" ? 1 : 2), unit, extra } -} - -function scopePercentExtra(rows = [], total = sumBy(rows, "value")) { - return rows.map((item) => ({ - ...item, - extra: item.extra || `占比 ${round((Number(item.value || 0) / Math.max(total, 1)) * 100, 1)}%`, - })) -} - -function sortScopeTownRows(rows = [], sortByValue = false) { - const order = new Map(hongyuanTownshipDisplayOrder.map((name, index) => [name, index])) - return [...rows].sort((a, b) => { - if (sortByValue) return Number(b.value || 0) - Number(a.value || 0) - const left = order.has(a.name) ? order.get(a.name) : 999 - const right = order.has(b.name) ? order.get(b.name) : 999 - return left - right || Number(b.value || 0) - Number(a.value || 0) - }) -} - -function buildScopeTownRows(stats = {}, key, fallbackMetricKey, unit = "万亩", options = {}) { - const rows = sortScopeTownRows(normalizeScopeRows(stats[key]), options.sortByValue === true) - .filter((item) => Number(item.value) > 0) - .map((item) => ({ ...item, unit: item.unit || unit })) - if (rows.length) return options.withPercent === false ? rows : scopePercentExtra(rows) - const fallbackValue = Number(stats[fallbackMetricKey] || 0) - return fallbackValue > 0 ? [scopeMetric(`${key}-total`, "全县合计", fallbackValue, unit)] : [] -} - -function buildScopeValueRows(stats = {}, key, fallbackMetricKey, fallbackName, unit = "万亩", limit = 6) { - const rows = normalizeScopeRows(stats[key]) - .filter((item) => Number(item.value) > 0) - .slice(0, limit) - .map((item) => ({ ...item, unit: item.unit || unit })) - if (rows.length) return scopePercentExtra(rows) - const fallbackValue = Number(stats[fallbackMetricKey] || 0) - return fallbackValue > 0 ? [scopeMetric(`${key}-total`, fallbackName, fallbackValue, unit)] : [] -} - -function hasMeaningfulRows(panel) { - return (panel?.rows || []).some((item) => Number(item.value) > 0) -} - -export function resolveEcologicalScopeStats(stats = {}) { - return stats && typeof stats === "object" ? stats : {} -} - -export function buildEcologicalScopePanels(stats = {}, viewKey = "natural-protected-area") { - stats = resolveEcologicalScopeStats(stats, viewKey) - const grasslandDistributionRows = buildScopeTownRows(stats, "grasslandDistribution", "grasslandAreaWanMu", "万亩") - const wetlandDistributionRows = buildScopeTownRows(stats, "wetlandDistribution", "wetlandAreaWanMu", "万亩") - const woodlandDistributionRows = buildScopeTownRows(stats, "woodlandDistribution", "woodlandAreaWanMu", "万亩", { - sortByValue: true, - }) - const grasslandProductivityRows = buildScopeTownRows(stats, "grasslandProductivity", "grasslandMuYieldJin", "斤/亩", { - withPercent: false, - }) - const grasslandTypeRows = buildScopeValueRows(stats, "grasslandTypes", "grasslandAreaWanMu", "草地面积") - const grasslandLevelRows = buildScopeValueRows(stats, "grasslandLevels", "grasslandAreaWanMu", "草地面积") - const woodlandQualityRows = buildScopeValueRows(stats, "woodlandQuality", "woodlandAreaWanMu", "林地面积") - const resourceStructureRows = scopePercentExtra([ - { key: `${viewKey}-scope-grassland`, name: "草地资源", value: Number(stats.grasslandAreaWanMu || 0), unit: "万亩" }, - { key: `${viewKey}-scope-wetland`, name: "湿地资源", value: Number(stats.wetlandAreaWanMu || 0), unit: "万亩" }, - { key: `${viewKey}-scope-woodland`, name: "林地资源", value: Number(stats.woodlandAreaWanMu || 0), unit: "万亩" }, - ].filter((item) => Number(item.value) > 0)) - - return { - left: [ - { - key: `${viewKey}-grassland-distribution`, - title: "草地分布", - type: "column", - variant: "plain", - labelMode: "horizontal", - scrollable: false, - span: 1, - rows: grasslandDistributionRows, - }, - { - key: `${viewKey}-wetland-distribution`, - title: "湿地面积", - type: "rank", - labelMode: "horizontal", - scrollable: false, - span: 1, - rows: wetlandDistributionRows, - }, - { - key: `${viewKey}-woodland-distribution`, - title: "林地分布", - type: "split", - variant: "compact", - span: 1, - rows: woodlandDistributionRows, - }, - { - key: `${viewKey}-grassland-productivity`, - title: "草地生产力", - type: "line", - fixedType: true, - labelMode: "horizontal", - span: 1, - rows: grasslandProductivityRows, - }, - ].filter(hasMeaningfulRows), - right: [ - { - key: `${viewKey}-grassland-type`, - title: "草原类型", - type: "donut", - variant: "ring", - span: 1, - rows: grasslandTypeRows, - }, - { - key: `${viewKey}-grassland-level`, - title: "草原级占比", - type: "rose", - span: 1, - rows: grasslandLevelRows, - }, - { - key: `${viewKey}-woodland-quality`, - title: "林地质量", - type: "heat", - limit: 6, - span: 1, - rows: woodlandQualityRows, - }, - { - key: `${viewKey}-resource-structure`, - title: "林草湿面积构成", - type: "structure", - span: 1, - rows: resourceStructureRows, - }, - ].filter(hasMeaningfulRows), - } -} - -export function getEcologicalScopeTopStats(stats = {}, viewKey = "natural-protected-area") { - stats = resolveEcologicalScopeStats(stats, viewKey) - const scopeName = "保护地" - return [ - { zh: `${scopeName}面积`, value: round(stats.scopeAreaWanMu, 2), unit: "万亩", decimals: 2, icon: "park" }, - { zh: "草地面积", value: round(stats.grasslandAreaWanMu, 2), unit: "万亩", decimals: 2, icon: "grass-basic" }, - { zh: "湿地面积", value: round(stats.wetlandAreaWanMu, 2), unit: "万亩", decimals: 2, icon: "wetland" }, - { zh: "林地面积", value: round(stats.woodlandAreaWanMu, 2), unit: "万亩", decimals: 2, icon: "forest" }, - ] -} +export const buildEcologicalRedlinePanels = buildEcologicalDirectPanels +export const buildNaturalProtectedAreaPanels = buildEcologicalDirectPanels function normalizeEcologicalRows(value = []) { let rows = value @@ -557,7 +379,7 @@ export const centerMapNotes = { } export function getEcologicalMapRanking(viewKey, stats = {}) { - if (viewKey === "ecological-redline" || ecologicalScopeViewKeys.includes(viewKey)) { + if (["ecological-redline", "natural-protected-area"].includes(viewKey)) { return { status: "success", title: viewKey === "natural-protected-area" ? "自然保护地" : "生态保护红线", diff --git a/src/views/ecologicalProtection/index.vue b/src/views/ecologicalProtection/index.vue index 610bb8b..4a32d85 100644 --- a/src/views/ecologicalProtection/index.vue +++ b/src/views/ecologicalProtection/index.vue @@ -15,13 +15,13 @@
- {{ redlineDataStateMessage }} + {{ ecologicalDirectDataStateMessage }}
@@ -197,12 +197,10 @@ import EngineeringAnalysisPanel from "./components/EngineeringAnalysisPanel.vue" import EngineeringStatisticsPanel from "./components/EngineeringStatisticsPanel.vue" import { buildEcologicalRedlinePanels, - buildEcologicalScopePanels, + buildNaturalProtectedAreaPanels, buildEcologicalRestorationPanels, buildNationalParkPanels, - ecologicalScopeViewKeys, engineeringAnalysisPanels, - getEcologicalScopeTopStats, getEcologicalMapRanking, getEcologicalRestorationTopStats, getNationalParkTopStats, @@ -229,7 +227,8 @@ const activeLayerKey = ref("") const selectedLegendKey = ref("") const redlinePanels = ref(buildEcologicalRedlinePanels()) const redlineDataState = ref("loading") -const scopePanels = ref(buildEcologicalScopePanels({}, "natural-protected-area")) +const naturalProtectedAreaPanels = ref(buildNaturalProtectedAreaPanels()) +const naturalProtectedAreaDataState = ref("loading") const nationalParkPanels = ref(buildNationalParkPanels({})) const restorationPanels = ref(buildEcologicalRestorationPanels({})) const selectedFeature = ref(null) @@ -254,14 +253,14 @@ let destroyed = false let mapAssetsReady = false let mapLoadStarted = false let mapLoadTimer = null -let scopeStatsRequestId = 0 let redlineStatsRequestId = 0 +let naturalProtectedAreaStatsRequestId = 0 let nationalParkStatsRequestId = 0 let restorationStatsRequestId = 0 let engineeringAnalysisRequestId = 0 let featureQueryRequestId = 0 -const scopeStatsCache = new Map() let redlineStatsCache = null +let naturalProtectedAreaStatsCache = null let nationalParkStatsCache = null let restorationStatsCache = null let engineeringAnalysisCache = null @@ -297,11 +296,16 @@ const currentView = computed(() => const isEngineeringAnalysis = computed(() => currentView.value === "engineering-analysis") const isProjectDetailView = computed(() => ["restoration", "engineering-analysis"].includes(currentView.value)) const isEcologicalRedlineView = computed(() => currentView.value === "ecological-redline") -const isEcologicalScopeView = computed(() => ecologicalScopeViewKeys.includes(currentView.value)) -const redlineDataStateMessage = computed(() => { - if (redlineDataState.value === "loading") return "生态保护红线数据加载中" - if (redlineDataState.value === "empty") return "生态保护红线暂无数据" - if (redlineDataState.value === "error") return "生态保护红线数据加载失败,请稍后重试" +const isNaturalProtectedAreaView = computed(() => currentView.value === "natural-protected-area") +const isEcologicalDirectView = computed(() => isEcologicalRedlineView.value || isNaturalProtectedAreaView.value) +const ecologicalDirectDataState = computed(() => ( + isEcologicalRedlineView.value ? redlineDataState.value : naturalProtectedAreaDataState.value +)) +const ecologicalDirectDataStateMessage = computed(() => { + const featureName = isEcologicalRedlineView.value ? "生态保护红线" : "自然保护地" + if (ecologicalDirectDataState.value === "loading") return `${featureName}数据加载中` + if (ecologicalDirectDataState.value === "empty") return `${featureName}暂无数据` + if (ecologicalDirectDataState.value === "error") return `${featureName}数据加载失败,请稍后重试` return "" }) const baseActiveLayer = computed(() => activeLayerKey.value ? getLayerByKey(currentView.value, activeLayerKey.value) : null) @@ -337,7 +341,7 @@ const activeLayer = computed(() => { }) const currentPanels = computed(() => { if (isEcologicalRedlineView.value) return redlinePanels.value - if (isEcologicalScopeView.value) return scopePanels.value + if (isNaturalProtectedAreaView.value) return naturalProtectedAreaPanels.value if (currentView.value === "restoration") return restorationPanels.value if (currentView.value === "engineering-analysis") return engineeringAnalysisPanels return nationalParkPanels.value @@ -422,6 +426,7 @@ function syncView(viewKey) { const isRestoration = viewKey === "restoration" const isEngineering = viewKey === "engineering-analysis" const isRedline = viewKey === "ecological-redline" + const isNaturalProtectedArea = viewKey === "natural-protected-area" mapRanking.value = getEcologicalMapRanking(viewKey) mapSceneRef.value?.setBoundaryDrawing?.(false) mapSceneRef.value?.clearAnalysisBoundary?.() @@ -430,8 +435,9 @@ function syncView(viewKey) { if (isRedline) { redlineDataState.value = "loading" redlinePanels.value = buildEcologicalRedlinePanels() - } else if (ecologicalScopeViewKeys.includes(viewKey)) { - scopePanels.value = buildEcologicalScopePanels({}, viewKey) + } else if (isNaturalProtectedArea) { + naturalProtectedAreaDataState.value = "loading" + naturalProtectedAreaPanels.value = buildNaturalProtectedAreaPanels() } if (isNationalPark) { nationalParkPanels.value = buildNationalParkPanels({}) @@ -446,10 +452,8 @@ function syncView(viewKey) { emit("module-stats", { moduleKey: "ecological-protection", viewKey, - items: isRedline + items: isRedline || isNaturalProtectedArea ? [] - : ecologicalScopeViewKeys.includes(viewKey) - ? getEcologicalScopeTopStats({}, viewKey) : isNationalPark ? getNationalParkTopStats({}) : isRestoration @@ -458,8 +462,8 @@ function syncView(viewKey) { }) if (isRedline) { loadEcologicalRedlineStats(viewKey) - } else if (ecologicalScopeViewKeys.includes(viewKey)) { - loadEcologicalScopeStats(viewKey) + } else if (isNaturalProtectedArea) { + loadNaturalProtectedAreaStats(viewKey) } else if (isNationalPark) { loadNationalParkStats(viewKey) } else if (isRestoration) { @@ -568,32 +572,35 @@ function handleViewSelect(viewKey) { emit("view-change", nextKey) } -async function loadEcologicalScopeStats(viewKey) { - const requestId = ++scopeStatsRequestId +async function loadNaturalProtectedAreaStats(viewKey) { + const requestId = ++naturalProtectedAreaStatsRequestId + naturalProtectedAreaDataState.value = "loading" + naturalProtectedAreaPanels.value = buildNaturalProtectedAreaPanels() try { - const cached = scopeStatsCache.get(viewKey) - const stats = cached || await getNaturalProtectedAreaStats() - if (requestId !== scopeStatsRequestId || currentView.value !== viewKey) return - scopeStatsCache.set(viewKey, stats) - scopePanels.value = buildEcologicalScopePanels(stats, viewKey) + const stats = naturalProtectedAreaStatsCache || await getNaturalProtectedAreaStats() + if (requestId !== naturalProtectedAreaStatsRequestId || currentView.value !== viewKey) return + naturalProtectedAreaStatsCache = stats + naturalProtectedAreaDataState.value = stats.dataState + naturalProtectedAreaPanels.value = buildNaturalProtectedAreaPanels(stats.panels) emit("module-stats", { moduleKey: "ecological-protection", viewKey, - items: getEcologicalScopeTopStats(stats, viewKey), + items: stats.topRows.rows, }) } catch (error) { - if (requestId !== scopeStatsRequestId || currentView.value !== viewKey) return - scopePanels.value = buildEcologicalScopePanels({}, viewKey) + if (requestId !== naturalProtectedAreaStatsRequestId || currentView.value !== viewKey) return + naturalProtectedAreaDataState.value = "error" + naturalProtectedAreaPanels.value = buildNaturalProtectedAreaPanels() emit("module-stats", { moduleKey: "ecological-protection", viewKey, - items: getEcologicalScopeTopStats({}, viewKey), + items: [], }) layerStatus.value = { type: "error", - text: "保护范围统计加载失败", + text: "自然保护地统计加载失败", } - console.warn("Failed to load ecological scope statistics", error) + console.warn("Failed to load natural-protected-area statistics", error) } } diff --git a/src/views/forestGrassWet/components/FeatureInfoPanel.vue b/src/views/forestGrassWet/components/FeatureInfoPanel.vue index 2208ad1..4a8f7a0 100644 --- a/src/views/forestGrassWet/components/FeatureInfoPanel.vue +++ b/src/views/forestGrassWet/components/FeatureInfoPanel.vue @@ -742,6 +742,16 @@ const isEcologicalRedlineFeature = computed(() => { return layerKey.includes("ecological-redline") || layerName.includes("resource_ecological_redline_boundary") }) +const isNaturalProtectedAreaFeature = computed(() => { + const layerKey = String(props.feature?.layer?.key || "").toLowerCase() + const layerName = String(props.feature?.layer?.layerName || "").toLowerCase() + return layerKey.includes("natural-protected-area") || layerName.includes("resource_natural_protected_area_boundary") +}) + +const isServerOwnedEcologicalAreaFeature = computed(() => ( + isEcologicalRedlineFeature.value || isNaturalProtectedAreaFeature.value +)) + const isEngineeringSuitabilityFeature = computed(() => { const layerKey = String(props.feature?.layer?.key || "").toLowerCase() return layerKey.includes("engineering-suitability") || Boolean(propsData.value.engineering_name) @@ -768,10 +778,11 @@ const displayRows = computed(() => { const useCompactGrassland = (isGrassland || activeTopicKey.value === "wetland") && props.compactGrassland const businessFields = useCompactGrassland ? grasslandCoreBusinessFields : topicBusinessFields[activeTopicKey.value] || topicBusinessFields.woodland businessFields.forEach(([keys, label]) => { - const redlineArea = isEcologicalRedlineFeature.value && isEcologicalAreaLabel(label, keys) + const ecologicalArea = isServerOwnedEcologicalAreaFeature.value && String(label) === "图斑面积" + const areaKeys = isEcologicalRedlineFeature.value ? ["area_mu"] : ["area_source_mj"] const row = buildRow( propsData.value, - redlineArea ? ["area_mu"] : keys, + ecologicalArea ? areaKeys : keys, resolveDisplayLabel(label, keys), used, ) @@ -780,11 +791,12 @@ const displayRows = computed(() => { used.add(row.sourceKey) } }) - if (isEcologicalRedlineFeature.value && !rows.some((row) => row.label === "图斑面积")) { - addStaticRow(rows, used, "图斑面积", "数据缺失", "area_mu-missing") + if (isServerOwnedEcologicalAreaFeature.value && !rows.some((row) => row.label === "图斑面积")) { + const sourceKey = isEcologicalRedlineFeature.value ? "area_mu" : "area_source_mj" + addStaticRow(rows, used, "图斑面积", "数据缺失", `${sourceKey}-missing`) } const areaLabel = getTopicAreaLabel(activeTopicKey.value) - if (!isEcologicalRedlineFeature.value && !isArtificialGrassland.value && !isEngineeringSuitabilityFeature.value && !rows.some((row) => row.label === areaLabel || isGenericPatchAreaLabel(row.label))) { + if (!isServerOwnedEcologicalAreaFeature.value && !isArtificialGrassland.value && !isEngineeringSuitabilityFeature.value && !rows.some((row) => row.label === areaLabel || isGenericPatchAreaLabel(row.label))) { addStaticRow(rows, used, areaLabel, formatGeometryArea(featureGeometry.value), "geometry-area") } if (useCompactGrassland) return rows.slice(0, 10) @@ -914,8 +926,8 @@ function addStaticRow(rows, used, label, value, sourceKey) { used.add(sourceKey) } -function resolveDisplayLabel(label, keys = []) { - if (activeTopicKey.value === "ecological" && isEcologicalScopeFeature.value && isEcologicalAreaLabel(label, keys)) { +function resolveDisplayLabel(label) { + if (activeTopicKey.value === "ecological" && isServerOwnedEcologicalAreaFeature.value && String(label) === "图斑面积") { return "图斑面积" } if (isGenericPatchAreaLabel(label)) return getTopicAreaLabel(activeTopicKey.value) @@ -926,11 +938,6 @@ function isGenericPatchAreaLabel(label) { return ["图斑面积", "图斑地类面积", "小班面积"].includes(String(label || "")) } -function isEcologicalAreaLabel(label, keys = []) { - if (String(label || "") === "治理面积" || isGenericPatchAreaLabel(label)) return true - return keys.some((key) => patchAreaFieldKeys.has(key)) -} - function getTopicAreaLabel(topicKey) { if (topicKey === "grassland" || topicKey === "artificial-grassland") return "草地面积" if (topicKey === "wetland") return "湿地面积" @@ -988,7 +995,7 @@ function formatValue(key, value) { if (patchAreaFieldKeys.has(key) && number === 0) return "" if (number === 0 && zeroHiddenKeys.has(key)) return "" const formatted = Number.isInteger(number) ? `${number}` : `${Number(number.toFixed(2))}` - if (key === "area_source_mj") return `${formatAreaWanMu(number * 15)} 万亩` + if (key === "area_source_mj") return formatted if (activeTopicKey.value === "ecological" && isEcologicalScopeFeature.value && ["area_mu", "acreage", "mj"].includes(key)) return `${formatAreaWanMu(number)} 万亩` if (activeTopicKey.value === "ecological" && isEcologicalScopeFeature.value && ["area_m2", "original_area_m2", "adjusted_area_m2"].includes(key)) return `${formatAreaWanMu(number / 666.6667)} 万亩` if (["xbmj", "tbdlmj", "geomj", "area_square_meter"].includes(key)) return `${formatAreaMu(number / 666.6667)} 亩`