|
|
@@ -4,7 +4,7 @@
|
|
|
<div class="left-sidebar">
|
|
|
<div class="data-card">
|
|
|
<div class="card-header" @click="toggleBasicData">
|
|
|
- <h3 class="card-title">基础数据</h3>
|
|
|
+ <h3 class="card-title">水资源评价</h3>
|
|
|
<div class="header-actions">
|
|
|
<span class="toggle-btn">{{ basicDataExpanded ? '▼' : '▶' }}</span>
|
|
|
</div>
|
|
|
@@ -12,61 +12,33 @@
|
|
|
<div v-if="basicDataExpanded" class="card-body">
|
|
|
<div class="basic-data-content">
|
|
|
<div class="data-item">
|
|
|
- <div class="data-label">当前库容</div>
|
|
|
- <div class="data-value">2350.8 万m³</div>
|
|
|
+ <div class="data-label">多年平均</div>
|
|
|
+ <div class="data-value">{{ basicData.multiYearAverage }} 万m³</div>
|
|
|
</div>
|
|
|
<div class="data-item">
|
|
|
- <div class="data-label">可用水量</div>
|
|
|
- <div class="data-value">1820.5 万m³</div>
|
|
|
+ <div class="data-label">今年已来水</div>
|
|
|
+ <div class="data-value">{{ basicData.currentYearInflow }} 万m³</div>
|
|
|
</div>
|
|
|
- <div class="data-item">
|
|
|
- <div class="data-label">日均需水</div>
|
|
|
- <div class="data-value">85.2 万m³</div>
|
|
|
- </div>
|
|
|
- <div class="data-item">
|
|
|
- <div class="data-label">日均供水</div>
|
|
|
- <div class="data-value">82.6 万m³</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="data-card mt-20">
|
|
|
- <div class="card-header" @click="toggleReservoirStatus">
|
|
|
- <h3 class="card-title">水库状态</h3>
|
|
|
- <div class="header-actions">
|
|
|
- <span class="toggle-btn">{{ reservoirStatusExpanded ? '▼' : '▶' }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div v-if="reservoirStatusExpanded" class="card-body">
|
|
|
- <div class="reservoir-list">
|
|
|
- <div class="reservoir-item" v-for="(res, index) in reservoirs" :key="index">
|
|
|
- <div class="reservoir-name">{{ res.name }}</div>
|
|
|
- <div class="reservoir-level" :class="res.level > res.capacity * 0.8 ? 'warning' : 'normal'">
|
|
|
- {{ res.level.toFixed(1) }}m
|
|
|
- </div>
|
|
|
- <div class="reservoir-capacity">
|
|
|
- {{ (res.level / res.capacity * 100).toFixed(0) }}%
|
|
|
+ <div class="data-item" :class="getAnomalyClass()">
|
|
|
+ <div class="data-label">同期距平</div>
|
|
|
+ <div class="data-value" :class="basicData.anomalyPercent >= 0 ? 'positive' : 'negative'">
|
|
|
+ {{ basicData.anomalyPercent >= 0 ? '+' : '' }}{{ basicData.anomalyPercent }} %
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <canvas id="anomalyChart" width="380" height="280"></canvas>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="data-card mt-20">
|
|
|
<div class="card-header" @click="toggleAllocationPlan">
|
|
|
- <h3 class="card-title">调配方案</h3>
|
|
|
+ <h3 class="card-title">土壤墒情</h3>
|
|
|
<div class="header-actions">
|
|
|
<span class="toggle-btn">{{ allocationPlanExpanded ? '▼' : '▶' }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div v-if="allocationPlanExpanded" class="card-body">
|
|
|
- <div class="allocation-content">
|
|
|
- <div class="chart-box">
|
|
|
- <div class="chart-title">今日水资源分配</div>
|
|
|
- <canvas id="allocationChart" width="300" height="180"></canvas>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <canvas id="allocationChart" width="350" height="280"></canvas>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -185,6 +157,7 @@ export default {
|
|
|
demandAnalysisExpanded: true,
|
|
|
allocationChart: null,
|
|
|
demandStructureChart: null,
|
|
|
+ anomalyChart: null,
|
|
|
showDatePicker: false,
|
|
|
startDate: formatDate(weekAgo),
|
|
|
endDate: formatDate(today),
|
|
|
@@ -192,16 +165,37 @@ export default {
|
|
|
currentMonth: today.getMonth(),
|
|
|
currentYear: today.getFullYear(),
|
|
|
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
|
|
|
+ basicData: {
|
|
|
+ multiYearAverage: 285.6,
|
|
|
+ currentYearInflow: 85.6,
|
|
|
+ anomalyPercent: 9.6
|
|
|
+ },
|
|
|
+ anomalyData: {
|
|
|
+ months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
|
|
+ currentYearCumulative: [15.2, 32.8, 48.5, 65.3, 85.6, 102.5, 118.2, 132.8, 147.5, 162.2, 176.5, 190.8],
|
|
|
+ multiYearAverageCumulative: [14.5, 30.2, 45.8, 62.5, 80.3, 95.6, 110.8, 125.2, 139.5, 153.8, 168.2, 182.5]
|
|
|
+ },
|
|
|
reservoirs: [
|
|
|
{ name: '小塔山水库', level: 18.6, capacity: 22.5 },
|
|
|
{ name: '吴山水库', level: 12.3, capacity: 15.0 },
|
|
|
{ name: '陡沟水库', level: 8.5, capacity: 10.0 }
|
|
|
],
|
|
|
- demands: [
|
|
|
- { name: '农业灌溉', value: 45.8, percent: 68 },
|
|
|
- { name: '居民生活', value: 12.3, percent: 18 },
|
|
|
- { name: '生态环境', value: 9.1, percent: 14 }
|
|
|
- ],
|
|
|
+ soilMoistureData: {
|
|
|
+ dates: [],
|
|
|
+ historical: {
|
|
|
+ layer10: [],
|
|
|
+ layer20: [],
|
|
|
+ layer40: []
|
|
|
+ },
|
|
|
+ forecast: {
|
|
|
+ layer10: [],
|
|
|
+ layer20: [],
|
|
|
+ layer40: []
|
|
|
+ },
|
|
|
+ suitableRange: [0, 0],
|
|
|
+ lightDroughtRange: [0, 0],
|
|
|
+ severeDroughtRange: [0, 0]
|
|
|
+ },
|
|
|
demandData: {
|
|
|
totalDemand: 67.2,
|
|
|
changePercent: 5.3,
|
|
|
@@ -253,16 +247,28 @@ export default {
|
|
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
|
|
|
this.generateDemandTrendData(start, end, diffDays)
|
|
|
this.generateDemandComparisonData()
|
|
|
+ this.generateSoilMoistureData()
|
|
|
setTimeout(() => {
|
|
|
this.initCharts()
|
|
|
this.initDemandTrendChart()
|
|
|
this.initDemandComparisonChart()
|
|
|
+ this.initAnomalyChart()
|
|
|
+ this.initAllocationChart()
|
|
|
}, 100)
|
|
|
},
|
|
|
beforeUnmount() {
|
|
|
this.destroyCharts()
|
|
|
},
|
|
|
methods: {
|
|
|
+ getAnomalyClass() {
|
|
|
+ if (this.basicData.anomalyPercent > 0) {
|
|
|
+ return 'abundant'
|
|
|
+ } else if (this.basicData.anomalyPercent < 0) {
|
|
|
+ return 'dry'
|
|
|
+ } else {
|
|
|
+ return 'normal'
|
|
|
+ }
|
|
|
+ },
|
|
|
formatDate(date) {
|
|
|
const year = date.getFullYear()
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
|
@@ -321,6 +327,19 @@ export default {
|
|
|
},
|
|
|
toggleBasicData() {
|
|
|
this.basicDataExpanded = !this.basicDataExpanded
|
|
|
+ if (this.basicDataExpanded) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.initAnomalyChart()
|
|
|
+ }, 100)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toggleAnomalyChart() {
|
|
|
+ this.anomalyChartExpanded = !this.anomalyChartExpanded
|
|
|
+ if (this.anomalyChartExpanded) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.initAnomalyChart()
|
|
|
+ }, 100)
|
|
|
+ }
|
|
|
},
|
|
|
toggleReservoirStatus() {
|
|
|
this.reservoirStatusExpanded = !this.reservoirStatusExpanded
|
|
|
@@ -399,6 +418,7 @@ export default {
|
|
|
const totalDemand = []
|
|
|
const agriculturalDemand = []
|
|
|
const residentialDemand = []
|
|
|
+ const evaporation = []
|
|
|
const heilinInflow = []
|
|
|
const xiaotaishanSupply = []
|
|
|
|
|
|
@@ -410,16 +430,19 @@ export default {
|
|
|
|
|
|
const baseAg = 6.5
|
|
|
const baseRes = 1.8
|
|
|
+ const baseEvap = 1.2
|
|
|
const factor = 0.8 + Math.random() * 0.4
|
|
|
|
|
|
const ag = parseFloat((baseAg * factor).toFixed(1))
|
|
|
const res = parseFloat((baseRes * factor).toFixed(1))
|
|
|
+ const evap = parseFloat((baseEvap * factor).toFixed(1))
|
|
|
const total = parseFloat((ag + res).toFixed(1))
|
|
|
const inflow = parseFloat((total * (0.7 + Math.random() * 0.6)).toFixed(1))
|
|
|
const supply = parseFloat((total * (0.8 + Math.random() * 0.5)).toFixed(1))
|
|
|
|
|
|
agriculturalDemand.push(ag)
|
|
|
residentialDemand.push(res)
|
|
|
+ evaporation.push(evap)
|
|
|
totalDemand.push(total)
|
|
|
heilinInflow.push(inflow)
|
|
|
xiaotaishanSupply.push(supply)
|
|
|
@@ -432,17 +455,18 @@ export default {
|
|
|
totalDemand,
|
|
|
agriculturalDemand,
|
|
|
residentialDemand,
|
|
|
+ evaporation,
|
|
|
heilinInflow,
|
|
|
xiaotaishanSupply
|
|
|
}
|
|
|
},
|
|
|
generateDemandComparisonData() {
|
|
|
- const currentData = [45.8, 12.3]
|
|
|
- const lastYearData = [42.5, 11.8]
|
|
|
- const lastMonthData = [44.2, 12.0]
|
|
|
+ const currentData = [45.8, 12.3, 8.5]
|
|
|
+ const lastYearData = [42.5, 11.8, 7.9]
|
|
|
+ const lastMonthData = [44.2, 12.0, 8.2]
|
|
|
|
|
|
this.demandComparisonData = {
|
|
|
- categories: ['农业灌溉', '居民用水'],
|
|
|
+ categories: ['农业灌溉', '居民用水', '蒸发量'],
|
|
|
current: currentData,
|
|
|
lastYear: lastYearData,
|
|
|
lastMonth: lastMonthData
|
|
|
@@ -461,6 +485,58 @@ export default {
|
|
|
if (this.demandComparisonChart) {
|
|
|
this.demandComparisonChart.dispose()
|
|
|
}
|
|
|
+ if (this.anomalyChart) {
|
|
|
+ this.anomalyChart.dispose()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ generateSoilMoistureData() {
|
|
|
+ const today = new Date()
|
|
|
+ const dates = []
|
|
|
+ const historicalLayer10 = []
|
|
|
+ const historicalLayer20 = []
|
|
|
+ const historicalLayer40 = []
|
|
|
+ const forecastLayer10 = []
|
|
|
+ const forecastLayer20 = []
|
|
|
+ const forecastLayer40 = []
|
|
|
+
|
|
|
+ for (let i = 6; i >= 0; i--) {
|
|
|
+ const date = new Date(today.getTime() - i * 24 * 60 * 60 * 1000)
|
|
|
+ const month = date.getMonth() + 1
|
|
|
+ const day = date.getDate()
|
|
|
+ dates.push(`${month}月${day}日`)
|
|
|
+
|
|
|
+ historicalLayer10.push(23 + (Math.random() - 0.5) * 6)
|
|
|
+ historicalLayer20.push(28 + (Math.random() - 0.5) * 6)
|
|
|
+ historicalLayer40.push(43 + (Math.random() - 0.5) * 6)
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let i = 1; i <= 3; i++) {
|
|
|
+ const date = new Date(today.getTime() + i * 24 * 60 * 60 * 1000)
|
|
|
+ const month = date.getMonth() + 1
|
|
|
+ const day = date.getDate()
|
|
|
+ dates.push(`${month}月${day}日`)
|
|
|
+
|
|
|
+ forecastLayer10.push(23 + (Math.random() - 0.5) * 6)
|
|
|
+ forecastLayer20.push(28 + (Math.random() - 0.5) * 6)
|
|
|
+ forecastLayer40.push(43 + (Math.random() - 0.5) * 6)
|
|
|
+ }
|
|
|
+
|
|
|
+ this.soilMoistureData = {
|
|
|
+ dates,
|
|
|
+ historical: {
|
|
|
+ layer10: historicalLayer10,
|
|
|
+ layer20: historicalLayer20,
|
|
|
+ layer40: historicalLayer40
|
|
|
+ },
|
|
|
+ forecast: {
|
|
|
+ layer10: forecastLayer10,
|
|
|
+ layer20: forecastLayer20,
|
|
|
+ layer40: forecastLayer40
|
|
|
+ },
|
|
|
+ suitableRange: [20, 35],
|
|
|
+ lightDroughtRange: [12, 20],
|
|
|
+ severeDroughtRange: [0, 12]
|
|
|
+ }
|
|
|
},
|
|
|
initAllocationChart() {
|
|
|
if (document.getElementById('allocationChart')) {
|
|
|
@@ -468,56 +544,228 @@ export default {
|
|
|
this.allocationChart.dispose()
|
|
|
}
|
|
|
this.allocationChart = echarts.init(document.getElementById('allocationChart'))
|
|
|
+
|
|
|
+ const { dates, historical, forecast, suitableRange, lightDroughtRange, severeDroughtRange } = this.soilMoistureData
|
|
|
+ const historicalData = dates.map((date, index) => {
|
|
|
+ if (index < 7) {
|
|
|
+ return historical.layer10[index]
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ })
|
|
|
+ const forecastData10 = dates.map((date, index) => {
|
|
|
+ if (index >= 7) {
|
|
|
+ return forecast.layer10[index - 7]
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ })
|
|
|
+ const forecastData20 = dates.map((date, index) => {
|
|
|
+ if (index >= 7) {
|
|
|
+ return forecast.layer20[index - 7]
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ })
|
|
|
+ const forecastData40 = dates.map((date, index) => {
|
|
|
+ if (index >= 7) {
|
|
|
+ return forecast.layer40[index - 7]
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
const option = {
|
|
|
animation: false,
|
|
|
tooltip: {
|
|
|
- trigger: 'item',
|
|
|
- formatter: '{b}: {c}万m³ ({d}%)'
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ type: 'cross'
|
|
|
+ },
|
|
|
+ formatter: (params) => {
|
|
|
+ let result = `${params[0].name}<br/>`
|
|
|
+ params.forEach((param) => {
|
|
|
+ if (param.seriesName === '-10cm') {
|
|
|
+ result += `${param.seriesName}:${param.data ? param.data.toFixed(1) : '-'}%<br/>`
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: 30,
|
|
|
+ right: 30,
|
|
|
+ bottom: 60,
|
|
|
+ top: 40,
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: dates,
|
|
|
+ axisLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: '#7bbef6'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#ffffff',
|
|
|
+ fontSize: 10,
|
|
|
+ interval: 0,
|
|
|
+ rotate: 45
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ name: '土壤含水率(%)',
|
|
|
+ nameLocation: 'end',
|
|
|
+ nameGap: 5,
|
|
|
+ nameTextStyle: {
|
|
|
+ color: '#ffffff',
|
|
|
+ fontSize: 11,
|
|
|
+ align: 'left',
|
|
|
+ verticalAlign: 'bottom',
|
|
|
+ padding: [0, 0, 0, -15]
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: '#7bbef6'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#ffffff',
|
|
|
+ fontSize: 10
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: 'rgba(123, 190, 246, 0.2)'
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
legend: {
|
|
|
- orient: 'vertical',
|
|
|
- left: 'left',
|
|
|
+ data: ['-10cm', '-20cm', '-40cm'],
|
|
|
textStyle: {
|
|
|
- color: '#7bbef6',
|
|
|
+ color: '#ffffff',
|
|
|
fontSize: 10
|
|
|
},
|
|
|
- itemWidth: 10,
|
|
|
- itemHeight: 10,
|
|
|
- itemGap: 6
|
|
|
+ itemWidth: 12,
|
|
|
+ itemHeight: 12,
|
|
|
+ itemGap: 8,
|
|
|
+ bottom: '0%'
|
|
|
+ },
|
|
|
+ markArea: {
|
|
|
+ silent: true,
|
|
|
+ itemStyle: {
|
|
|
+ opacity: 0.3
|
|
|
+ },
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ name: '适宜区间',
|
|
|
+ xAxis: 0,
|
|
|
+ yAxis: suitableRange[0],
|
|
|
+ label: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ itemStyle: {
|
|
|
+ color: '#4ade80'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '适宜区间',
|
|
|
+ xAxis: dates.length - 1,
|
|
|
+ yAxis: suitableRange[1],
|
|
|
+ label: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ itemStyle: {
|
|
|
+ color: '#4ade80'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
},
|
|
|
series: [
|
|
|
{
|
|
|
- name: '水资源分配',
|
|
|
- type: 'pie',
|
|
|
- radius: '60%',
|
|
|
- avoidLabelOverlap: false,
|
|
|
- label: {
|
|
|
- show: true,
|
|
|
- position: 'outside',
|
|
|
- formatter: '{b}: {c}万m³ ({d}%)',
|
|
|
- color: '#e0fcff',
|
|
|
- fontSize: 11
|
|
|
+ name: '-10cm',
|
|
|
+ type: 'line',
|
|
|
+ data: dates.map((date, index) => {
|
|
|
+ if (index < 7) {
|
|
|
+ return historical.layer10[index]
|
|
|
+ } else if (index >= 7) {
|
|
|
+ return forecast.layer10[index - 7]
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ }),
|
|
|
+ smooth: true,
|
|
|
+ itemStyle: {
|
|
|
+ color: (params) => {
|
|
|
+ if (params.dataIndex >= 7) {
|
|
|
+ return '#ffd93d'
|
|
|
+ }
|
|
|
+ return '#62f6fb'
|
|
|
+ }
|
|
|
},
|
|
|
- emphasis: {
|
|
|
- label: {
|
|
|
- show: true,
|
|
|
- fontSize: 12,
|
|
|
- fontWeight: 'bold',
|
|
|
- color: '#e0fcff'
|
|
|
+ lineStyle: {
|
|
|
+ color: '#62f6fb',
|
|
|
+ width: 2,
|
|
|
+ type: (params) => {
|
|
|
+ return params.dataIndex >= 7 ? 'dashed' : 'solid'
|
|
|
}
|
|
|
},
|
|
|
- labelLine: {
|
|
|
- show: true,
|
|
|
- lineStyle: {
|
|
|
- color: '#7bbef6'
|
|
|
- },
|
|
|
- length: 10,
|
|
|
- length2: 15
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 4
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '-20cm',
|
|
|
+ type: 'line',
|
|
|
+ data: dates.map((date, index) => {
|
|
|
+ if (index < 7) {
|
|
|
+ return historical.layer20[index]
|
|
|
+ } else if (index >= 7) {
|
|
|
+ return forecast.layer20[index - 7]
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ }),
|
|
|
+ smooth: true,
|
|
|
+ itemStyle: {
|
|
|
+ color: (params) => {
|
|
|
+ if (params.dataIndex >= 7) {
|
|
|
+ return '#ffd93d'
|
|
|
+ }
|
|
|
+ return '#38bdf8'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: '#38bdf8',
|
|
|
+ width: 2,
|
|
|
+ type: (params) => {
|
|
|
+ return params.dataIndex >= 7 ? 'dashed' : 'solid'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 4
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '-40cm',
|
|
|
+ type: 'line',
|
|
|
+ data: dates.map((date, index) => {
|
|
|
+ if (index < 7) {
|
|
|
+ return historical.layer40[index]
|
|
|
+ } else if (index >= 7) {
|
|
|
+ return forecast.layer40[index - 7]
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ }),
|
|
|
+ smooth: true,
|
|
|
+ itemStyle: {
|
|
|
+ color: (params) => {
|
|
|
+ if (params.dataIndex >= 7) {
|
|
|
+ return '#ffd93d'
|
|
|
+ }
|
|
|
+ return '#22c55e'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: '#22c55e',
|
|
|
+ width: 2,
|
|
|
+ type: 'solid'
|
|
|
},
|
|
|
- data: [
|
|
|
- { value: 45.8, name: '农业灌溉', itemStyle: { color: '#62f6fb' } },
|
|
|
- { value: 12.3, name: '居民用水', itemStyle: { color: '#38bdf8' } }
|
|
|
- ]
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 4
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
@@ -539,10 +787,10 @@ export default {
|
|
|
animation: false,
|
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
|
- formatter: '{b}<br/>{a0}: {c0}万m³<br/>{a1}: {c1}万m³<br/>{a2}: {c2}万m³<br/>{a3}: {c3}万m³'
|
|
|
+ formatter: '{b}<br/>{a0}: {c0}万m³<br/>{a1}: {c1}万m³<br/>{a2}: {c2}万m³<br/>{a3}: {c3}万m³<br/>{a4}: {c4}万m³'
|
|
|
},
|
|
|
legend: {
|
|
|
- data: ['农业灌溉', '居民用水', '黑林水文站来水', '小塔山水库供水'],
|
|
|
+ data: ['农业灌溉', '居民用水', '蒸发量', '黑林水文站来水', '小塔山水库供水'],
|
|
|
textStyle: {
|
|
|
color: '#e0fcff',
|
|
|
fontSize: 11
|
|
|
@@ -620,6 +868,15 @@ export default {
|
|
|
color: '#a78bfa'
|
|
|
}
|
|
|
},
|
|
|
+ {
|
|
|
+ name: '蒸发量',
|
|
|
+ type: 'bar',
|
|
|
+ stack: 'total',
|
|
|
+ data: this.demandTrendData.evaporation,
|
|
|
+ itemStyle: {
|
|
|
+ color: '#fbbf24'
|
|
|
+ }
|
|
|
+ },
|
|
|
{
|
|
|
name: '黑林水文站来水',
|
|
|
type: 'line',
|
|
|
@@ -808,6 +1065,138 @@ export default {
|
|
|
]
|
|
|
}
|
|
|
this.demandComparisonChart.setOption(option)
|
|
|
+ },
|
|
|
+ initAnomalyChart() {
|
|
|
+ if (document.getElementById('anomalyChart')) {
|
|
|
+ if (this.anomalyChart) {
|
|
|
+ this.anomalyChart.dispose()
|
|
|
+ }
|
|
|
+ this.anomalyChart = echarts.init(document.getElementById('anomalyChart'))
|
|
|
+
|
|
|
+ const { months, currentYearCumulative, multiYearAverageCumulative } = this.anomalyData
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ animation: false,
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ type: 'line'
|
|
|
+ },
|
|
|
+ formatter: (params) => {
|
|
|
+ let result = `${params[0].name}<br/>`
|
|
|
+ params.forEach((param) => {
|
|
|
+ const isForecast = param.dataIndex >= 5
|
|
|
+ const diff = param.data - (param.seriesName === '今年累计' ? multiYearAverageCumulative[param.dataIndex] : currentYearCumulative[param.dataIndex])
|
|
|
+ const diffPercent = ((diff / (param.seriesName === '今年累计' ? multiYearAverageCumulative[param.dataIndex] : currentYearCumulative[param.dataIndex])) * 100).toFixed(1)
|
|
|
+ const sign = diff >= 0 ? '+' : ''
|
|
|
+ const label = isForecast && param.seriesName === '今年累计' ? '(预报)' : ''
|
|
|
+ result += `${param.seriesName}:${param.data}万m³${label} (${sign}${diff}万m³, ${sign}${diffPercent}%)<br/>`
|
|
|
+ })
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ data: ['今年累计', '多年同期平均累计'],
|
|
|
+ textStyle: {
|
|
|
+ color: '#ffffff',
|
|
|
+ fontSize: 11
|
|
|
+ },
|
|
|
+ itemWidth: 12,
|
|
|
+ itemHeight: 12,
|
|
|
+ itemGap: 8,
|
|
|
+ bottom: '0%'
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: 0,
|
|
|
+ right: 55,
|
|
|
+ bottom: 45,
|
|
|
+ top: 25,
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: months,
|
|
|
+ axisLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: '#7bbef6'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#ffffff',
|
|
|
+ fontSize: 10,
|
|
|
+ interval: 0,
|
|
|
+ rotate: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ name: '累计水量(万m³)',
|
|
|
+ nameLocation: 'end',
|
|
|
+ nameGap: 5,
|
|
|
+ nameTextStyle: {
|
|
|
+ color: '#ffffff',
|
|
|
+ fontSize: 11,
|
|
|
+ align: 'left',
|
|
|
+ verticalAlign: 'bottom',
|
|
|
+ padding: [0, 0, 0, -15]
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: '#7bbef6'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#ffffff',
|
|
|
+ fontSize: 10,
|
|
|
+ formatter: (value) => {
|
|
|
+ return value > 0 ? `+${value}` : value
|
|
|
+ }
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: 'rgba(123, 190, 246, 0.2)'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '今年累计',
|
|
|
+ type: 'line',
|
|
|
+ data: currentYearCumulative,
|
|
|
+ smooth: true,
|
|
|
+ itemStyle: {
|
|
|
+ color: (params) => {
|
|
|
+ return params.dataIndex >= 5 ? '#ffd93d' : '#62f6fb'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: (params) => {
|
|
|
+ return params.dataIndex >= 5 ? '#ffd93d' : '#62f6fb'
|
|
|
+ },
|
|
|
+ width: 2
|
|
|
+ },
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 6
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '多年同期平均累计',
|
|
|
+ type: 'line',
|
|
|
+ data: multiYearAverageCumulative,
|
|
|
+ smooth: true,
|
|
|
+ itemStyle: {
|
|
|
+ color: '#a78bfa'
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ width: 2,
|
|
|
+ type: 'dashed'
|
|
|
+ },
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 6
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ this.anomalyChart.setOption(option)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -893,18 +1282,44 @@ export default {
|
|
|
|
|
|
.basic-data-content {
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
+ flex-direction: row;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
.data-item {
|
|
|
+ flex: 1;
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
align-items: center;
|
|
|
- padding: 8px 12px;
|
|
|
+ padding: 15px 10px;
|
|
|
background: rgba(0, 20, 40, 0.5);
|
|
|
border-radius: 4px;
|
|
|
border: 1px solid rgba(0, 212, 255, 0.2);
|
|
|
+ min-height: 80px;
|
|
|
+}
|
|
|
+
|
|
|
+.data-item.abundant {
|
|
|
+ border-color: #4ade80;
|
|
|
+ box-shadow: 0 0 15px rgba(74, 222, 128, 0.6), 0 0 30px rgba(74, 222, 128, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+.data-item.dry {
|
|
|
+ border-color: #ff6b6b;
|
|
|
+ box-shadow: 0 0 15px rgba(255, 107, 107, 0.6), 0 0 30px rgba(255, 107, 107, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+.data-item.normal {
|
|
|
+ border-color: #9ca3af;
|
|
|
+ box-shadow: 0 0 15px rgba(156, 163, 175, 0.6), 0 0 30px rgba(156, 163, 175, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+.data-item .data-label {
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.data-item .data-value {
|
|
|
+ font-size: 16px;
|
|
|
}
|
|
|
|
|
|
.data-label {
|
|
|
@@ -918,6 +1333,14 @@ export default {
|
|
|
font-weight: bold;
|
|
|
}
|
|
|
|
|
|
+.data-value.positive {
|
|
|
+ color: #4ade80;
|
|
|
+}
|
|
|
+
|
|
|
+.data-value.negative {
|
|
|
+ color: #ff6b6b;
|
|
|
+}
|
|
|
+
|
|
|
.reservoir-list {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|