|
|
|
@ -138,20 +138,27 @@ |
|
|
|
:disabled="homeVideoRows.length <= 1" |
|
|
|
:disabled="homeVideoRows.length <= 1" |
|
|
|
@click="showPrevVideo" |
|
|
|
@click="showPrevVideo" |
|
|
|
>‹</button> |
|
|
|
>‹</button> |
|
|
|
|
|
|
|
<div class="home-video-grid" :class="{ 'is-single': visibleHomeVideos.length <= 1 }"> |
|
|
|
<div |
|
|
|
<div |
|
|
|
:key="panel.live.key" |
|
|
|
v-for="item in visibleHomeVideos" |
|
|
|
:ref="setHomeVideoScreenRef" |
|
|
|
:key="item.key" |
|
|
|
|
|
|
|
:ref="(el) => setHomeVideoItemRef(el, item)" |
|
|
|
class="home-video-screen" |
|
|
|
class="home-video-screen" |
|
|
|
:class="{ 'is-playing': videoPlaying, 'is-loading': videoLoading }" |
|
|
|
:class="{ |
|
|
|
:style="videoScreenStyle(panel.live)" |
|
|
|
'is-active': item.isActive, |
|
|
|
@click="playCurrentVideo" |
|
|
|
'is-playing': videoPlaying && item.isActive, |
|
|
|
|
|
|
|
'is-loading': videoLoading && item.isActive, |
|
|
|
|
|
|
|
}" |
|
|
|
|
|
|
|
:style="videoScreenStyle(item.live, item.isActive)" |
|
|
|
|
|
|
|
@click="playHomeVideoAt(item.index)" |
|
|
|
> |
|
|
|
> |
|
|
|
<div :id="videoElementId" class="home-video-player"></div> |
|
|
|
<div v-if="item.isActive" :id="videoElementId" class="home-video-player"></div> |
|
|
|
<div v-if="!videoPlaying" class="home-video-scan"></div> |
|
|
|
<div v-if="!videoPlaying || !item.isActive" class="home-video-scan"></div> |
|
|
|
<div v-if="!videoPlaying && panel.live.hdPlayUrl" class="home-video-play"></div> |
|
|
|
<div v-if="(!videoPlaying || !item.isActive) && item.live.hdPlayUrl" class="home-video-play"></div> |
|
|
|
<div v-if="videoLoading" class="home-video-loading">加载中</div> |
|
|
|
<div v-if="videoLoading && item.isActive" class="home-video-loading">加载中</div> |
|
|
|
<div v-if="videoError" class="home-video-error">{{ videoError }}</div> |
|
|
|
<div v-if="videoError && item.isActive" class="home-video-error">{{ videoError }}</div> |
|
|
|
<div class="home-video-point-name">{{ panel.live.title }}</div> |
|
|
|
<div class="home-video-point-name">{{ item.live.title }}</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<button |
|
|
|
<button |
|
|
|
class="home-video-nav home-video-next" |
|
|
|
class="home-video-nav home-video-next" |
|
|
|
@ -237,8 +244,10 @@ import { chartTooltip, withChartDefaults } from "@/utils/chartTheme" |
|
|
|
import { |
|
|
|
import { |
|
|
|
buildForecastSeries, |
|
|
|
buildForecastSeries, |
|
|
|
estimatedStock, |
|
|
|
estimatedStock, |
|
|
|
|
|
|
|
formatForecastDayLabel, |
|
|
|
forecastPeriods, |
|
|
|
forecastPeriods, |
|
|
|
getForecastPeriod, |
|
|
|
getForecastPeriod, |
|
|
|
|
|
|
|
getForecastMonthCount, |
|
|
|
structureRows, |
|
|
|
structureRows, |
|
|
|
} from "@/views/yakManagement/data" |
|
|
|
} from "@/views/yakManagement/data" |
|
|
|
import { balanceTownRows } from "@/views/grassLivestockBalance/data" |
|
|
|
import { balanceTownRows } from "@/views/grassLivestockBalance/data" |
|
|
|
@ -417,6 +426,7 @@ const activeVideoIndex = computed(() => { |
|
|
|
return (chartMotionTick.value + activeVideoManualIndex.value) % length |
|
|
|
return (chartMotionTick.value + activeVideoManualIndex.value) % length |
|
|
|
}) |
|
|
|
}) |
|
|
|
const currentHomeVideo = computed(() => homeVideoRows.value[activeVideoIndex.value] || emptyHomeVideo) |
|
|
|
const currentHomeVideo = computed(() => homeVideoRows.value[activeVideoIndex.value] || emptyHomeVideo) |
|
|
|
|
|
|
|
const visibleHomeVideos = computed(() => buildVideoPreviewRows(homeVideoRows.value, activeVideoIndex.value, emptyHomeVideo)) |
|
|
|
|
|
|
|
|
|
|
|
const leftPanels = computed(() => [ |
|
|
|
const leftPanels = computed(() => [ |
|
|
|
pickTopicPanel("grassland", "grassland-town"), |
|
|
|
pickTopicPanel("grassland", "grassland-town"), |
|
|
|
@ -833,6 +843,28 @@ function setHomeVideoScreenRef(el) { |
|
|
|
homeVideoScreenRef.value = el || null |
|
|
|
homeVideoScreenRef.value = el || null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function setHomeVideoItemRef(el, item) { |
|
|
|
|
|
|
|
if (item?.isActive) homeVideoScreenRef.value = el || null |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function buildVideoPreviewRows(rows = [], activeIndex = 0, emptyRow = emptyHomeVideo) { |
|
|
|
|
|
|
|
const sourceRows = Array.isArray(rows) ? rows : [] |
|
|
|
|
|
|
|
if (!sourceRows.length) { |
|
|
|
|
|
|
|
return [{ key: `empty-${emptyRow.key || "video"}`, index: 0, live: emptyRow, isActive: true }] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const count = Math.min(2, sourceRows.length) |
|
|
|
|
|
|
|
return Array.from({ length: count }, (_, offset) => { |
|
|
|
|
|
|
|
const index = (activeIndex + offset + sourceRows.length) % sourceRows.length |
|
|
|
|
|
|
|
const live = sourceRows[index] || emptyRow |
|
|
|
|
|
|
|
return { |
|
|
|
|
|
|
|
key: `${live.key || live.title || "video"}-${index}`, |
|
|
|
|
|
|
|
index, |
|
|
|
|
|
|
|
live, |
|
|
|
|
|
|
|
isActive: index === activeIndex, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function startChartMotion() { |
|
|
|
function startChartMotion() { |
|
|
|
if (!props.active || destroyed) return |
|
|
|
if (!props.active || destroyed) return |
|
|
|
stopChartMotion() |
|
|
|
stopChartMotion() |
|
|
|
@ -877,9 +909,9 @@ async function loadHomeMonitorings() { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function videoScreenStyle(live) { |
|
|
|
function videoScreenStyle(live, isActive = true) { |
|
|
|
const image = live?.image || liveSceneImage |
|
|
|
const image = live?.image || liveSceneImage |
|
|
|
return videoPlaying.value |
|
|
|
return videoPlaying.value && isActive |
|
|
|
? undefined |
|
|
|
? undefined |
|
|
|
: { |
|
|
|
: { |
|
|
|
backgroundImage: `linear-gradient(180deg, rgba(0, 16, 26, 0.08), rgba(0, 16, 26, 0.32)), url(${image})`, |
|
|
|
backgroundImage: `linear-gradient(180deg, rgba(0, 16, 26, 0.08), rgba(0, 16, 26, 0.32)), url(${image})`, |
|
|
|
@ -903,6 +935,21 @@ function stepVideo(step) { |
|
|
|
chartMotionTick.value = 0 |
|
|
|
chartMotionTick.value = 0 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function playHomeVideoAt(index) { |
|
|
|
|
|
|
|
const length = homeVideoRows.value.length |
|
|
|
|
|
|
|
if (!length) { |
|
|
|
|
|
|
|
void playCurrentVideo() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const targetIndex = ((Number(index) || 0) + length) % length |
|
|
|
|
|
|
|
if (targetIndex !== activeVideoIndex.value || videoPlayer || videoLoading.value) { |
|
|
|
|
|
|
|
stopVideoPlayer({ resetError: true }) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
activeVideoManualIndex.value = targetIndex |
|
|
|
|
|
|
|
chartMotionTick.value = 0 |
|
|
|
|
|
|
|
void nextTick(playCurrentVideo) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function homeBalanceGaugeProgress(item) { |
|
|
|
function homeBalanceGaugeProgress(item) { |
|
|
|
const value = Math.max(0, Number(item?.value || 0)) |
|
|
|
const value = Math.max(0, Number(item?.value || 0)) |
|
|
|
const maxValue = Math.max(5, ...homeBalanceRows.value.map((row) => Math.max(0, Number(row.value || 0)))) |
|
|
|
const maxValue = Math.max(5, ...homeBalanceRows.value.map((row) => Math.max(0, Number(row.value || 0)))) |
|
|
|
@ -1337,14 +1384,13 @@ function getForecastGranularity(key) { |
|
|
|
function buildForecastSeriesByGranularity(period, granularityKey = "month") { |
|
|
|
function buildForecastSeriesByGranularity(period, granularityKey = "month") { |
|
|
|
if (granularityKey === "month") return buildForecastSeries(period) |
|
|
|
if (granularityKey === "month") return buildForecastSeries(period) |
|
|
|
|
|
|
|
|
|
|
|
const dayCount = Math.max(1, Math.round(Number(period.months || 0) * 30)) |
|
|
|
const monthCount = getForecastMonthCount(period) |
|
|
|
|
|
|
|
const dayCount = Math.max(1, Math.round(Math.max(1, monthCount - 1) * 30)) |
|
|
|
const stepDays = granularityKey === "week" ? 7 : 1 |
|
|
|
const stepDays = granularityKey === "week" ? 7 : 1 |
|
|
|
const count = Math.ceil(dayCount / stepDays) + 1 |
|
|
|
const count = Math.ceil(dayCount / stepDays) + 1 |
|
|
|
const labels = Array.from({ length: count }, (_, index) => { |
|
|
|
const labels = Array.from({ length: count }, (_, index) => { |
|
|
|
const day = Math.min(dayCount, index * stepDays) |
|
|
|
const day = Math.min(dayCount, index * stepDays) |
|
|
|
if (index === 0) return "2026-06" |
|
|
|
return formatForecastDayLabel(day) |
|
|
|
if (day >= dayCount) return period.label |
|
|
|
|
|
|
|
return granularityKey === "week" ? `第${index}周` : `第${day}日` |
|
|
|
|
|
|
|
}) |
|
|
|
}) |
|
|
|
const stock = labels.map((_, index) => { |
|
|
|
const stock = labels.map((_, index) => { |
|
|
|
const day = Math.min(dayCount, index * stepDays) |
|
|
|
const day = Math.min(dayCount, index * stepDays) |
|
|
|
@ -2114,20 +2160,32 @@ function handleOutsideFeaturePointerDown(event) { |
|
|
|
position: relative; |
|
|
|
position: relative; |
|
|
|
display: block; |
|
|
|
display: block; |
|
|
|
height: 100%; |
|
|
|
height: 100%; |
|
|
|
padding: 2px 18px; |
|
|
|
padding: 2px 24px; |
|
|
|
box-sizing: border-box; |
|
|
|
box-sizing: border-box; |
|
|
|
pointer-events: auto; |
|
|
|
pointer-events: auto; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.home-video-grid { |
|
|
|
|
|
|
|
display: grid; |
|
|
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr)); |
|
|
|
|
|
|
|
gap: 8px; |
|
|
|
|
|
|
|
height: 100%; |
|
|
|
|
|
|
|
min-height: 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.home-video-grid.is-single { |
|
|
|
|
|
|
|
grid-template-columns: minmax(0, 1fr); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.home-video-screen { |
|
|
|
.home-video-screen { |
|
|
|
position: relative; |
|
|
|
position: relative; |
|
|
|
width: 88%; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
height: 100%; |
|
|
|
margin: 0 auto; |
|
|
|
margin: 0; |
|
|
|
min-width: 0; |
|
|
|
min-width: 0; |
|
|
|
overflow: hidden; |
|
|
|
overflow: hidden; |
|
|
|
cursor: pointer; |
|
|
|
cursor: pointer; |
|
|
|
border: 1px solid rgba(48, 220, 255, 0.34); |
|
|
|
border: 1px solid rgba(48, 220, 255, 0.25); |
|
|
|
background-color: #020d14; |
|
|
|
background-color: #020d14; |
|
|
|
background-position: center; |
|
|
|
background-position: center; |
|
|
|
background-size: cover; |
|
|
|
background-size: cover; |
|
|
|
@ -2137,6 +2195,18 @@ function handleOutsideFeaturePointerDown(event) { |
|
|
|
0 0 16px rgba(18, 145, 190, 0.14); |
|
|
|
0 0 16px rgba(18, 145, 190, 0.14); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.home-video-screen.is-active { |
|
|
|
|
|
|
|
border-color: rgba(126, 251, 246, 0.66); |
|
|
|
|
|
|
|
box-shadow: |
|
|
|
|
|
|
|
inset 0 0 0 1px rgba(10, 255, 214, 0.12), |
|
|
|
|
|
|
|
inset 0 0 26px rgba(48, 220, 255, 0.18), |
|
|
|
|
|
|
|
0 0 18px rgba(18, 202, 204, 0.18); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.home-video-screen:not(.is-active) { |
|
|
|
|
|
|
|
opacity: 0.88; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.home-video-screen.is-playing { |
|
|
|
.home-video-screen.is-playing { |
|
|
|
background-image: none !important; |
|
|
|
background-image: none !important; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -2187,11 +2257,11 @@ function handleOutsideFeaturePointerDown(event) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.home-video-prev { |
|
|
|
.home-video-prev { |
|
|
|
left: 25px; |
|
|
|
left: 18px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.home-video-next { |
|
|
|
.home-video-next { |
|
|
|
right: 25px; |
|
|
|
right: 18px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.home-video-screen::before { |
|
|
|
.home-video-screen::before { |
|
|
|
|