|
|
|
@ -176,6 +176,10 @@ |
|
|
|
:autoresize="true" |
|
|
|
:autoresize="true" |
|
|
|
/> |
|
|
|
/> |
|
|
|
<div v-else-if="panel.key === 'home-town-balance-gauge'" class="home-balance-gauge-grid"> |
|
|
|
<div v-else-if="panel.key === 'home-town-balance-gauge'" class="home-balance-gauge-grid"> |
|
|
|
|
|
|
|
<div v-if="!homeBalanceGaugeRows.length" class="home-balance-empty" aria-live="polite"> |
|
|
|
|
|
|
|
<i></i> |
|
|
|
|
|
|
|
<span>{{ homeBalanceEmptyText }}</span> |
|
|
|
|
|
|
|
</div> |
|
|
|
<div |
|
|
|
<div |
|
|
|
v-for="(item, index) in homeBalanceGaugeRows" |
|
|
|
v-for="(item, index) in homeBalanceGaugeRows" |
|
|
|
:key="item.key" |
|
|
|
:key="item.key" |
|
|
|
@ -355,7 +359,8 @@ import { |
|
|
|
getForecastMonthCount, |
|
|
|
getForecastMonthCount, |
|
|
|
structureRows, |
|
|
|
structureRows, |
|
|
|
} from "@/views/yakManagement/data" |
|
|
|
} from "@/views/yakManagement/data" |
|
|
|
import { balanceTownRows } from "@/views/grassLivestockBalance/data" |
|
|
|
import { getAreaBalanceRows } from "@/services/balanceApi" |
|
|
|
|
|
|
|
import { normalizeBalanceResult } from "@/views/grassLivestockBalance/data" |
|
|
|
import { |
|
|
|
import { |
|
|
|
homeTopStats, |
|
|
|
homeTopStats, |
|
|
|
yakTownRows, |
|
|
|
yakTownRows, |
|
|
|
@ -470,6 +475,7 @@ let featureQueryRequestId = 0 |
|
|
|
let threeHomeAssets = null |
|
|
|
let threeHomeAssets = null |
|
|
|
let threeHomeAssetLoading = false |
|
|
|
let threeHomeAssetLoading = false |
|
|
|
let threeHomeAssetLoaded = false |
|
|
|
let threeHomeAssetLoaded = false |
|
|
|
|
|
|
|
let homeBalanceLoadSerial = 0 |
|
|
|
const homeVideoFitRafs = new Map() |
|
|
|
const homeVideoFitRafs = new Map() |
|
|
|
const chartMotionTick = ref(0) |
|
|
|
const chartMotionTick = ref(0) |
|
|
|
const homeVideoRows = ref([]) |
|
|
|
const homeVideoRows = ref([]) |
|
|
|
@ -481,6 +487,9 @@ const homeVideoModalPage = ref(1) |
|
|
|
const homeVideoRotationPaused = ref(false) |
|
|
|
const homeVideoRotationPaused = ref(false) |
|
|
|
const homeVideoExpandedIndex = ref(null) |
|
|
|
const homeVideoExpandedIndex = ref(null) |
|
|
|
const homeBalanceModalVisible = ref(false) |
|
|
|
const homeBalanceModalVisible = ref(false) |
|
|
|
|
|
|
|
const homeBalanceSourceRows = ref([]) |
|
|
|
|
|
|
|
const homeBalanceLoading = ref(false) |
|
|
|
|
|
|
|
const homeBalanceLoadError = ref("") |
|
|
|
const activeForecastGranularity = ref("month") |
|
|
|
const activeForecastGranularity = ref("month") |
|
|
|
const videoPlaying = ref(false) |
|
|
|
const videoPlaying = ref(false) |
|
|
|
const videoLoading = ref(false) |
|
|
|
const videoLoading = ref(false) |
|
|
|
@ -650,7 +659,7 @@ const activeForecastGranularityMeta = computed(() => getForecastGranularity(acti |
|
|
|
const trendSeries = computed(() => buildForecastSeriesByGranularity(forecastTrendPeriod, activeForecastGranularityMeta.value.key)) |
|
|
|
const trendSeries = computed(() => buildForecastSeriesByGranularity(forecastTrendPeriod, activeForecastGranularityMeta.value.key)) |
|
|
|
const activeForecastTrendIndex = computed(() => getLoopIndex(trendSeries.value.labels.length)) |
|
|
|
const activeForecastTrendIndex = computed(() => getLoopIndex(trendSeries.value.labels.length)) |
|
|
|
const homeBalanceRows = computed(() => { |
|
|
|
const homeBalanceRows = computed(() => { |
|
|
|
const rows = balanceTownRows.filter((item) => item?.name) |
|
|
|
const rows = homeBalanceSourceRows.value.filter((item) => item?.name && item.type === "town") |
|
|
|
return rows.map((item, index) => ({ |
|
|
|
return rows.map((item, index) => ({ |
|
|
|
key: `home-balance-${item.areaCode || item.key || item.name}`, |
|
|
|
key: `home-balance-${item.areaCode || item.key || item.name}`, |
|
|
|
sourceIndex: index, |
|
|
|
sourceIndex: index, |
|
|
|
@ -661,6 +670,10 @@ const homeBalanceRows = computed(() => { |
|
|
|
extra: `载畜 ${formatNumber(item.livestockCapacity)}头`, |
|
|
|
extra: `载畜 ${formatNumber(item.livestockCapacity)}头`, |
|
|
|
})) |
|
|
|
})) |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
const homeBalanceEmptyText = computed(() => { |
|
|
|
|
|
|
|
if (homeBalanceLoading.value) return "正在读取最新草畜平衡数据" |
|
|
|
|
|
|
|
return homeBalanceLoadError.value || "暂无草畜平衡数据" |
|
|
|
|
|
|
|
}) |
|
|
|
const homeBalanceGaugeRows = computed(() => { |
|
|
|
const homeBalanceGaugeRows = computed(() => { |
|
|
|
const rows = homeBalanceRows.value |
|
|
|
const rows = homeBalanceRows.value |
|
|
|
const pageSize = 3 |
|
|
|
const pageSize = 3 |
|
|
|
@ -1012,11 +1025,13 @@ onMounted(() => { |
|
|
|
document.addEventListener("pointerdown", handleOutsideFeaturePointerDown, true) |
|
|
|
document.addEventListener("pointerdown", handleOutsideFeaturePointerDown, true) |
|
|
|
document.addEventListener("click", handleHomeVideoDocumentClickCapture, true) |
|
|
|
document.addEventListener("click", handleHomeVideoDocumentClickCapture, true) |
|
|
|
emitHomeTopStats() |
|
|
|
emitHomeTopStats() |
|
|
|
|
|
|
|
void loadHomeBalanceRows() |
|
|
|
initHomeMap() |
|
|
|
initHomeMap() |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => { |
|
|
|
onBeforeUnmount(() => { |
|
|
|
destroyed = true |
|
|
|
destroyed = true |
|
|
|
|
|
|
|
homeBalanceLoadSerial += 1 |
|
|
|
window.removeEventListener("resize", updateHomeViewportHeight) |
|
|
|
window.removeEventListener("resize", updateHomeViewportHeight) |
|
|
|
window.removeEventListener("keydown", handleHomeKeyDown) |
|
|
|
window.removeEventListener("keydown", handleHomeKeyDown) |
|
|
|
document.removeEventListener("pointerdown", handleOutsideFeaturePointerDown, true) |
|
|
|
document.removeEventListener("pointerdown", handleOutsideFeaturePointerDown, true) |
|
|
|
@ -1063,6 +1078,7 @@ watch( |
|
|
|
initHomeMap() |
|
|
|
initHomeMap() |
|
|
|
restoreHomeMapOnActivate() |
|
|
|
restoreHomeMapOnActivate() |
|
|
|
startChartMotion() |
|
|
|
startChartMotion() |
|
|
|
|
|
|
|
void loadHomeBalanceRows() |
|
|
|
if (!homeIdleWorkLoaded) scheduleHomeIdleWork() |
|
|
|
if (!homeIdleWorkLoaded) scheduleHomeIdleWork() |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
homeMapReadyReported = false |
|
|
|
homeMapReadyReported = false |
|
|
|
@ -1501,6 +1517,35 @@ function openHomeBalanceModal() { |
|
|
|
homeBalanceModalVisible.value = true |
|
|
|
homeBalanceModalVisible.value = true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function loadHomeBalanceRows() { |
|
|
|
|
|
|
|
const loadId = ++homeBalanceLoadSerial |
|
|
|
|
|
|
|
homeBalanceLoading.value = true |
|
|
|
|
|
|
|
homeBalanceLoadError.value = "" |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
const sourceRows = await getAreaBalanceRows() |
|
|
|
|
|
|
|
if (destroyed || loadId !== homeBalanceLoadSerial) return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uniqueRows = new Map() |
|
|
|
|
|
|
|
sourceRows.forEach((sourceRow) => { |
|
|
|
|
|
|
|
const row = normalizeBalanceResult(sourceRow, sourceRow) |
|
|
|
|
|
|
|
if (row.type !== "town" || !row.name) return |
|
|
|
|
|
|
|
const identity = row.areaCode || row.key || row.name |
|
|
|
|
|
|
|
uniqueRows.set(String(identity), row) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
homeBalanceSourceRows.value = [...uniqueRows.values()].sort((left, right) => |
|
|
|
|
|
|
|
String(left.areaCode || left.name).localeCompare(String(right.areaCode || right.name), "zh-CN"), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
if (!homeBalanceSourceRows.value.length) homeBalanceLoadError.value = "暂未查询到最新草畜平衡数据" |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
if (destroyed || loadId !== homeBalanceLoadSerial) return |
|
|
|
|
|
|
|
console.warn("[home] balance rows unavailable", error) |
|
|
|
|
|
|
|
homeBalanceSourceRows.value = [] |
|
|
|
|
|
|
|
homeBalanceLoadError.value = "草畜平衡数据暂时无法连接" |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
if (!destroyed && loadId === homeBalanceLoadSerial) homeBalanceLoading.value = false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function closeHomeBalanceModal() { |
|
|
|
function closeHomeBalanceModal() { |
|
|
|
homeBalanceModalVisible.value = false |
|
|
|
homeBalanceModalVisible.value = false |
|
|
|
} |
|
|
|
} |
|
|
|
@ -3931,6 +3976,33 @@ function handleOutsideFeaturePointerDown(event) { |
|
|
|
overflow: hidden; |
|
|
|
overflow: hidden; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.home-balance-empty { |
|
|
|
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
grid-column: 1 / -1; |
|
|
|
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
justify-content: center; |
|
|
|
|
|
|
|
gap: 10px; |
|
|
|
|
|
|
|
color: rgba(238, 253, 255, 0.72); |
|
|
|
|
|
|
|
font-size: 14px; |
|
|
|
|
|
|
|
font-weight: 700; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i { |
|
|
|
|
|
|
|
width: 8px; |
|
|
|
|
|
|
|
height: 8px; |
|
|
|
|
|
|
|
border-radius: 50%; |
|
|
|
|
|
|
|
background: #30dcff; |
|
|
|
|
|
|
|
box-shadow: 0 0 12px rgba(48, 220, 255, 0.86); |
|
|
|
|
|
|
|
animation: home-balance-loading 1.25s ease-in-out infinite; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes home-balance-loading { |
|
|
|
|
|
|
|
50% { |
|
|
|
|
|
|
|
opacity: 0.3; |
|
|
|
|
|
|
|
transform: scale(0.72); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.home-balance-gauge-card { |
|
|
|
.home-balance-gauge-card { |
|
|
|
position: relative; |
|
|
|
position: relative; |
|
|
|
display: grid; |
|
|
|
display: grid; |
|
|
|
|