WQQ пре 5 дана
родитељ
комит
692f101515
1 измењених фајлова са 909 додато и 67 уклоњено
  1. 909 67
      src/views/WaterResourceAllocationView.vue

+ 909 - 67
src/views/WaterResourceAllocationView.vue

@@ -80,59 +80,81 @@
           </div>
         </div>
         <div v-if="demandAnalysisExpanded" class="card-body">
-          <div class="demand-list">
-            <div class="demand-item" v-for="(demand, index) in demands" :key="index">
-              <div class="demand-name">{{ demand.name }}</div>
-              <div class="demand-value">{{ demand.value }} 万m³</div>
-              <div class="demand-percent">{{ demand.percent }}%</div>
+          <div class="date-range-filter">
+            <div class="date-display" @click="showDatePicker = !showDatePicker">
+              <span class="date-text">{{ formatDateDisplay(startDate) }} 至 {{ formatDateDisplay(endDate) }}</span>
+              <span class="calendar-icon">📅</span>
             </div>
-          </div>
-        </div>
-      </div>
-
-      <div class="data-card mt-20">
-        <div class="card-header" @click="toggleOptimization">
-          <h3 class="card-title">优化建议</h3>
-          <div class="header-actions">
-            <span class="toggle-btn">{{ optimizationExpanded ? '▼' : '▶' }}</span>
-          </div>
-        </div>
-        <div v-if="optimizationExpanded" class="card-body">
-          <div class="suggestion-list">
-            <div class="suggestion-item" v-for="(sug, index) in suggestions" :key="index">
-              <div class="suggestion-icon">{{ sug.icon }}</div>
-              <div class="suggestion-text">{{ sug.text }}</div>
+            <div v-if="showDatePicker" class="date-picker-popup">
+              <div class="date-picker-header">
+                <button class="nav-btn" @click="prevMonth">&lt;</button>
+                <span class="current-month">{{ currentYear }}年{{ currentMonth + 1 }}月</span>
+                <button class="nav-btn" @click="nextMonth">&gt;</button>
+                <button class="close-btn" @click="showDatePicker = false">×</button>
+              </div>
+              <div class="calendar-container">
+                <div class="weekdays">
+                  <div v-for="day in weekdays" :key="day" class="weekday">{{ day }}</div>
+                </div>
+                <div class="days">
+                  <div 
+                    v-for="(date, index) in calendarDays" 
+                    :key="index"
+                    class="day"
+                    :class="{
+                      'empty': !date,
+                      'selected': isSelected(date),
+                      'in-range': isInRange(date),
+                      'start': isStartDate(date),
+                      'end': isEndDate(date),
+                      'today': isToday(date)
+                    }"
+                    @click="selectDate(date)"
+                  >
+                    {{ date ? new Date(date).getDate() : '' }}
+                  </div>
+                </div>
+              </div>
+              <div class="date-picker-footer">
+                <button class="confirm-btn" @click="confirmDateRange">确定</button>
+              </div>
             </div>
           </div>
-        </div>
-      </div>
-
-      <div class="data-card mt-20">
-        <div class="card-header" @click="toggleEffectPreview">
-          <h3 class="card-title">效果预演</h3>
-          <div class="header-actions">
-            <span class="toggle-btn">{{ effectPreviewExpanded ? '▼' : '▶' }}</span>
-          </div>
-        </div>
-        <div v-if="effectPreviewExpanded" class="card-body">
-          <div class="preview-content">
-            <div class="preview-stats">
-              <div class="stat-row">
-                <div class="stat-label">预计节水</div>
-                <div class="stat-value">+12.5%</div>
+          <div class="demand-cards">
+            <div class="demand-cards-row">
+              <div class="demand-card">
+                <div class="card-label">总需水量</div>
+                <div class="card-value">{{ demandData.totalDemand }} 万m³</div>
+                <div class="card-change" :class="demandData.changePercent >= 0 ? 'up' : 'down'">
+                  {{ demandData.changePercent >= 0 ? '+' : '' }}{{ demandData.changePercent }}%
+                </div>
               </div>
-              <div class="stat-row">
-                <div class="stat-label">供水保证率</div>
-                <div class="stat-value">98.2%</div>
+              <div class="demand-card">
+                <div class="card-label">供需状态</div>
+                <div class="card-value" :class="demandData.supplyStatus >= 0 ? 'surplus' : 'deficit'">
+                  {{ demandData.supplyStatus >= 0 ? '+' : '' }}{{ demandData.supplyStatus }} 万m³
+                </div>
+                <div class="card-status" :class="demandData.supplyStatus >= 0 ? 'surplus' : 'deficit'">
+                  {{ demandData.supplyStatus >= 0 ? '盈余' : '缺口' }}
+                </div>
               </div>
-              <div class="stat-row">
-                <div class="stat-label">生态流量</div>
-                <div class="stat-value">达标</div>
+            </div>
+            <div class="demand-trend-card">
+              <div class="chart-label">需水趋势</div>
+              <div class="chart-container">
+                <canvas id="demandTrendChart" width="320" height="240"></canvas>
+              </div>
+            </div>
+            <div class="demand-comparison-card">
+              <div class="chart-label">同期对比</div>
+              <div class="chart-container">
+                <canvas id="demandComparisonChart" width="320" height="260"></canvas>
               </div>
             </div>
           </div>
         </div>
       </div>
+
     </div>
   </div>
 </template>
@@ -148,14 +170,28 @@ export default {
   },
 
   data() {
+    const today = new Date()
+    const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000)
+    const formatDate = (date) => {
+      const year = date.getFullYear()
+      const month = String(date.getMonth() + 1).padStart(2, '0')
+      const day = String(date.getDate()).padStart(2, '0')
+      return `${year}-${month}-${day}`
+    }
     return {
       basicDataExpanded: true,
       reservoirStatusExpanded: true,
       allocationPlanExpanded: true,
       demandAnalysisExpanded: true,
-      optimizationExpanded: true,
-      effectPreviewExpanded: true,
       allocationChart: null,
+      demandStructureChart: null,
+      showDatePicker: false,
+      startDate: formatDate(weekAgo),
+      endDate: formatDate(today),
+      selectingStart: true,
+      currentMonth: today.getMonth(),
+      currentYear: today.getFullYear(),
+      weekdays: ['日', '一', '二', '三', '四', '五', '六'],
       reservoirs: [
         { name: '小塔山水库', level: 18.6, capacity: 22.5 },
         { name: '吴山水库', level: 12.3, capacity: 15.0 },
@@ -166,21 +202,123 @@ export default {
         { name: '居民生活', value: 12.3, percent: 18 },
         { name: '生态环境', value: 9.1, percent: 14 }
       ],
-      suggestions: [
-        { icon: '💧', text: '建议灌区采用滴灌技术' },
-        { icon: '🌱', text: '加强生态补水调度' }
-      ]
+      demandData: {
+        totalDemand: 67.2,
+        changePercent: 5.3,
+        supplyStatus: 15.4
+      },
+      demandTrendChart: null,
+      demandTrendData: {
+        dates: [],
+        totalDemand: [],
+        agriculturalDemand: [],
+        residentialDemand: [],
+        heilinInflow: [],
+        xiaotaishanSupply: []
+      },
+      demandComparisonChart: null,
+      demandComparisonData: {
+        categories: ['农业灌溉', '居民用水', '生态环境'],
+        current: [],
+        lastYear: [],
+        lastMonth: []
+      }
+    }
+  },
+  computed: {
+    calendarDays() {
+      const days = []
+      const firstDay = new Date(this.currentYear, this.currentMonth, 1)
+      const lastDay = new Date(this.currentYear, this.currentMonth + 1, 0)
+      
+      const firstDayOfWeek = firstDay.getDay()
+      const lastDateOfMonth = lastDay.getDate()
+      
+      for (let i = 0; i < firstDayOfWeek; i++) {
+        days.push(null)
+      }
+      
+      for (let day = 1; day <= lastDateOfMonth; day++) {
+        const date = new Date(this.currentYear, this.currentMonth, day)
+        days.push(this.formatDate(date))
+      }
+      
+      return days
     }
   },
   mounted() {
+    const start = new Date(this.startDate)
+    const end = new Date(this.endDate)
+    const diffTime = Math.abs(end - start)
+    const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
+    this.generateDemandTrendData(start, end, diffDays)
+    this.generateDemandComparisonData()
     setTimeout(() => {
       this.initCharts()
+      this.initDemandTrendChart()
+      this.initDemandComparisonChart()
     }, 100)
   },
   beforeUnmount() {
     this.destroyCharts()
   },
   methods: {
+    formatDate(date) {
+      const year = date.getFullYear()
+      const month = String(date.getMonth() + 1).padStart(2, '0')
+      const day = String(date.getDate()).padStart(2, '0')
+      return `${year}-${month}-${day}`
+    },
+    prevMonth() {
+      if (this.currentMonth === 0) {
+        this.currentMonth = 11
+        this.currentYear--
+      } else {
+        this.currentMonth--
+      }
+    },
+    nextMonth() {
+      if (this.currentMonth === 11) {
+        this.currentMonth = 0
+        this.currentYear++
+      } else {
+        this.currentMonth++
+      }
+    },
+    selectDate(date) {
+      if (!date) return
+      
+      if (this.selectingStart) {
+        this.startDate = date
+        this.endDate = date
+        this.selectingStart = false
+      } else {
+        if (date < this.startDate) {
+          this.endDate = this.startDate
+          this.startDate = date
+        } else {
+          this.endDate = date
+        }
+        this.selectingStart = true
+      }
+    },
+    isSelected(date) {
+      return date === this.startDate || date === this.endDate
+    },
+    isInRange(date) {
+      if (!date || !this.startDate || !this.endDate) return false
+      return date > this.startDate && date < this.endDate
+    },
+    isStartDate(date) {
+      return date === this.startDate
+    },
+    isEndDate(date) {
+      return date === this.endDate
+    },
+    isToday(date) {
+      const today = new Date()
+      return date === this.formatDate(today)
+    },
     toggleBasicData() {
       this.basicDataExpanded = !this.basicDataExpanded
     },
@@ -197,12 +335,118 @@ export default {
     },
     toggleDemandAnalysis() {
       this.demandAnalysisExpanded = !this.demandAnalysisExpanded
+      if (this.demandAnalysisExpanded) {
+        const start = new Date(this.startDate)
+        const end = new Date(this.endDate)
+        const diffTime = Math.abs(end - start)
+        const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
+        this.generateDemandTrendData(start, end, diffDays)
+        this.generateDemandComparisonData()
+        setTimeout(() => {
+          this.initDemandTrendChart()
+          this.initDemandComparisonChart()
+        }, 100)
+      }
     },
-    toggleOptimization() {
-      this.optimizationExpanded = !this.optimizationExpanded
+    formatDateDisplay(dateStr) {
+      if (!dateStr) return ''
+      const date = new Date(dateStr)
+      const year = date.getFullYear()
+      const month = String(date.getMonth() + 1).padStart(2, '0')
+      const day = String(date.getDate()).padStart(2, '0')
+      return `${year}-${month}-${day}`
     },
-    toggleEffectPreview() {
-      this.effectPreviewExpanded = !this.effectPreviewExpanded
+    confirmDateRange() {
+      this.showDatePicker = false
+      this.onDateRangeChange()
+    },
+    onDateRangeChange() {
+      if (!this.startDate || !this.endDate) return
+      
+      const start = new Date(this.startDate)
+      const end = new Date(this.endDate)
+      const diffTime = Math.abs(end - start)
+      const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
+      
+      let baseMultiplier = 1
+      if (diffDays <= 1) {
+        baseMultiplier = 0.14
+      } else if (diffDays <= 7) {
+        baseMultiplier = 1
+      } else if (diffDays <= 30) {
+        baseMultiplier = 4
+      } else {
+        baseMultiplier = diffDays / 7
+      }
+      
+      const randomFactor = 0.8 + Math.random() * 0.4
+      const multiplier = baseMultiplier * randomFactor
+      
+      this.demandData = {
+        totalDemand: parseFloat((67.2 * multiplier).toFixed(1)),
+        changePercent: parseFloat((3 + Math.random() * 5).toFixed(1)) * (Math.random() > 0.5 ? 1 : -1),
+        supplyStatus: parseFloat((15.4 * multiplier * (Math.random() > 0.5 ? 1 : -1)).toFixed(1))
+      }
+      
+      this.generateDemandTrendData(start, end, diffDays)
+      this.generateDemandComparisonData()
+      
+      this.updateDemandTrendChart()
+      this.updateDemandComparisonChart()
+    },
+    generateDemandTrendData(startDate, endDate, days) {
+      const dates = []
+      const totalDemand = []
+      const agriculturalDemand = []
+      const residentialDemand = []
+      const heilinInflow = []
+      const xiaotaishanSupply = []
+      
+      let current = new Date(startDate)
+      for (let i = 0; i <= days; i++) {
+        const month = current.getMonth() + 1
+        const day = current.getDate()
+        dates.push(`${month}月${day}日`)
+        
+        const baseAg = 6.5
+        const baseRes = 1.8
+        const factor = 0.8 + Math.random() * 0.4
+        
+        const ag = parseFloat((baseAg * factor).toFixed(1))
+        const res = parseFloat((baseRes * 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)
+        totalDemand.push(total)
+        heilinInflow.push(inflow)
+        xiaotaishanSupply.push(supply)
+        
+        current.setDate(current.getDate() + 1)
+      }
+      
+      this.demandTrendData = {
+        dates,
+        totalDemand,
+        agriculturalDemand,
+        residentialDemand,
+        heilinInflow,
+        xiaotaishanSupply
+      }
+    },
+    generateDemandComparisonData() {
+      const currentData = [45.8, 12.3]
+      const lastYearData = [42.5, 11.8]
+      const lastMonthData = [44.2, 12.0]
+      
+      this.demandComparisonData = {
+        categories: ['农业灌溉', '居民用水'],
+        current: currentData,
+        lastYear: lastYearData,
+        lastMonth: lastMonthData
+      }
     },
     initCharts() {
       this.initAllocationChart()
@@ -211,6 +455,12 @@ export default {
       if (this.allocationChart) {
         this.allocationChart.dispose()
       }
+      if (this.demandTrendChart) {
+        this.demandTrendChart.dispose()
+      }
+      if (this.demandComparisonChart) {
+        this.demandComparisonChart.dispose()
+      }
     },
     initAllocationChart() {
       if (document.getElementById('allocationChart')) {
@@ -228,45 +478,336 @@ export default {
             orient: 'vertical',
             left: 'left',
             textStyle: {
-              color: '#7bbef6'
-            }
+              color: '#7bbef6',
+              fontSize: 10
+            },
+            itemWidth: 10,
+            itemHeight: 10,
+            itemGap: 6
           },
           series: [
             {
               name: '水资源分配',
               type: 'pie',
-              radius: ['40%', '70%'],
+              radius: '60%',
               avoidLabelOverlap: false,
-              itemStyle: {
-                borderRadius: 10,
-                borderColor: 'rgba(0, 30, 60, 0.6)',
-                borderWidth: 2
-              },
               label: {
-                show: false,
-                position: 'center'
+                show: true,
+                position: 'outside',
+                formatter: '{b}: {c}万m³ ({d}%)',
+                color: '#e0fcff',
+                fontSize: 11
               },
               emphasis: {
                 label: {
                   show: true,
-                  fontSize: 14,
+                  fontSize: 12,
                   fontWeight: 'bold',
                   color: '#e0fcff'
                 }
               },
               labelLine: {
-                show: false
+                show: true,
+                lineStyle: {
+                  color: '#7bbef6'
+                },
+                length: 10,
+                length2: 15
               },
               data: [
                 { value: 45.8, name: '农业灌溉', itemStyle: { color: '#62f6fb' } },
-                { value: 12.3, name: '居民生活', itemStyle: { color: '#38bdf8' } },
-                { value: 9.1, name: '生态环境', itemStyle: { color: 'rgba(123, 190, 246, 0.5)' } }
+                { value: 12.3, name: '居民用水', itemStyle: { color: '#38bdf8' } }
               ]
             }
           ]
         }
         this.allocationChart.setOption(option)
       }
+    },
+    initDemandTrendChart() {
+      if (document.getElementById('demandTrendChart')) {
+        if (this.demandTrendChart) {
+          this.demandTrendChart.dispose()
+        }
+        this.demandTrendChart = echarts.init(document.getElementById('demandTrendChart'))
+        this.updateDemandTrendChart()
+      }
+    },
+    updateDemandTrendChart() {
+      if (!this.demandTrendChart) return
+      const option = {
+        animation: false,
+        tooltip: {
+          trigger: 'axis',
+          formatter: '{b}<br/>{a0}: {c0}万m³<br/>{a1}: {c1}万m³<br/>{a2}: {c2}万m³<br/>{a3}: {c3}万m³'
+        },
+        legend: {
+          data: ['农业灌溉', '居民用水', '黑林水文站来水', '小塔山水库供水'],
+          textStyle: {
+            color: '#e0fcff',
+            fontSize: 11
+          },
+          itemWidth: 12,
+          itemHeight: 12,
+          itemGap: 8,
+          bottom: '0%'
+        },
+        grid: {
+          left: 20,
+          right: 15,
+          bottom: 50,
+          top: 20,
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: true,
+          data: this.demandTrendData.dates,
+          axisLine: {
+            lineStyle: {
+              color: '#7bbef6'
+            }
+          },
+          axisLabel: {
+            color: '#7bbef6',
+            fontSize: 10
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '水量(万m³)',
+          nameLocation: 'end',
+          nameGap: 5,
+          nameTextStyle: {
+            color: '#7bbef6',
+            fontSize: 11,
+            align: 'left',
+            verticalAlign: 'bottom',
+            padding: [0, 0, 0, -15]
+          },
+          min: 0,
+          axisLine: {
+            lineStyle: {
+              color: '#7bbef6'
+            }
+          },
+          axisLabel: {
+            color: '#7bbef6',
+            fontSize: 10
+          },
+          splitLine: {
+            lineStyle: {
+              color: 'rgba(123, 190, 246, 0.2)'
+            }
+          }
+        },
+        series: [
+          {
+            name: '农业灌溉',
+            type: 'bar',
+            stack: 'total',
+            data: this.demandTrendData.agriculturalDemand,
+            itemStyle: {
+              color: '#38bdf8'
+            }
+          },
+          {
+            name: '居民用水',
+            type: 'bar',
+            stack: 'total',
+            data: this.demandTrendData.residentialDemand,
+            itemStyle: {
+              color: '#a78bfa'
+            }
+          },
+          {
+            name: '黑林水文站来水',
+            type: 'line',
+            data: this.demandTrendData.heilinInflow,
+            smooth: true,
+            itemStyle: {
+              color: '#f97316'
+            },
+            lineStyle: {
+              width: 2
+            }
+          },
+          {
+            name: '小塔山水库供水',
+            type: 'line',
+            data: this.demandTrendData.xiaotaishanSupply,
+            smooth: true,
+            itemStyle: {
+              color: '#22c55e'
+            },
+            lineStyle: {
+              width: 2
+            }
+          }
+        ]
+      }
+      this.demandTrendChart.setOption(option)
+    },
+    initDemandComparisonChart() {
+      if (document.getElementById('demandComparisonChart')) {
+        if (this.demandComparisonChart) {
+          this.demandComparisonChart.dispose()
+        }
+        this.demandComparisonChart = echarts.init(document.getElementById('demandComparisonChart'))
+        this.updateDemandComparisonChart()
+      }
+    },
+    updateDemandComparisonChart() {
+      if (!this.demandComparisonChart) return
+      const { categories, current, lastYear, lastMonth } = this.demandComparisonData
+      
+      const option = {
+        animation: false,
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow'
+          },
+          formatter: (params) => {
+            let result = params[0].name + '<br/>'
+            params.forEach((param) => {
+              const dataValue = typeof param.data === 'object' ? param.data.value : param.data
+              let diff = 0
+              let diffPercent = 0
+              if (param.seriesName === '去年同期') {
+                diff = current[param.dataIndex] - lastYear[param.dataIndex]
+                diffPercent = ((diff / lastYear[param.dataIndex]) * 100).toFixed(1)
+              } else if (param.seriesName === '上月同期') {
+                diff = current[param.dataIndex] - lastMonth[param.dataIndex]
+                diffPercent = ((diff / lastMonth[param.dataIndex]) * 100).toFixed(1)
+              }
+              result += `${param.seriesName}: ${dataValue}万m³`
+              if (param.seriesName !== '当期') {
+                const sign = diff >= 0 ? '+' : ''
+                result += ` (${sign}${diff.toFixed(1)}万m³, ${sign}${diffPercent}%)`
+              }
+              result += '<br/>'
+            })
+            return result
+          }
+        },
+        legend: {
+          data: ['当期', '去年同期', '上月同期'],
+          textStyle: {
+            color: '#e0fcff',
+            fontSize: 10
+          },
+          itemWidth: 10,
+          itemHeight: 10,
+          itemGap: 6,
+          bottom: '5%'
+        },
+        grid: {
+          left: 20,
+          right: 15,
+          bottom: 45,
+          top: 20,
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: categories,
+          axisLine: {
+            lineStyle: {
+              color: '#7bbef6'
+            }
+          },
+          axisLabel: {
+            color: '#7bbef6',
+            fontSize: 10
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '水量(万m³)',
+          nameLocation: 'end',
+          nameGap: 5,
+          nameTextStyle: {
+            color: '#7bbef6',
+            fontSize: 11,
+            align: 'left',
+            verticalAlign: 'bottom',
+            padding: [0, 0, 0, -15]
+          },
+          min: 0,
+          axisLine: {
+            lineStyle: {
+              color: '#7bbef6'
+            }
+          },
+          axisLabel: {
+            color: '#7bbef6',
+            fontSize: 9
+          },
+          splitLine: {
+            lineStyle: {
+              color: 'rgba(123, 190, 246, 0.2)'
+            }
+          }
+        },
+        series: [
+          {
+            name: '当期',
+            type: 'bar',
+            data: current,
+            itemStyle: { color: '#38bdf8' },
+            label: {
+              show: true,
+              position: 'top',
+              color: '#e0fcff',
+              fontSize: 9,
+              formatter: (params) => {
+                return params.value.toFixed(1)
+              }
+            },
+            barWidth: '20%'
+          },
+          {
+            name: '去年同期',
+            type: 'bar',
+            data: lastYear,
+            itemStyle: { color: '#f97316' },
+            label: {
+              show: true,
+              position: 'top',
+              color: '#e0fcff',
+              fontSize: 8,
+              formatter: (params) => {
+                const diff = current[params.dataIndex] - lastYear[params.dataIndex]
+                const diffPercent = ((diff / lastYear[params.dataIndex]) * 100).toFixed(1)
+                const sign = diff >= 0 ? '+' : ''
+                return `${sign}${diff.toFixed(1)}\n${sign}${diffPercent}%`
+              }
+            },
+            barWidth: '20%'
+          },
+          {
+            name: '上月同期',
+            type: 'bar',
+            data: lastMonth,
+            itemStyle: { color: '#22c55e' },
+            label: {
+              show: true,
+              position: 'top',
+              color: '#e0fcff',
+              fontSize: 8,
+              formatter: (params) => {
+                const diff = current[params.dataIndex] - lastMonth[params.dataIndex]
+                const diffPercent = ((diff / lastMonth[params.dataIndex]) * 100).toFixed(1)
+                const sign = diff >= 0 ? '+' : ''
+                return `${sign}${diff.toFixed(1)}\n${sign}${diffPercent}%`
+              }
+            },
+            barWidth: '20%'
+          }
+        ]
+      }
+      this.demandComparisonChart.setOption(option)
     }
   }
 }
@@ -520,4 +1061,305 @@ export default {
   font-size: 14px;
   font-weight: bold;
 }
+
+.date-range-filter {
+  margin-bottom: 8px;
+  position: relative;
+}
+
+.date-display {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 4px 8px;
+  background: rgba(0, 20, 40, 0.5);
+  border: 1px solid rgba(0, 212, 255, 0.2);
+  border-radius: 4px;
+  color: #e0fcff;
+  font-size: 12px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.date-display:hover {
+  border-color: rgba(0, 212, 255, 0.5);
+  background: rgba(0, 20, 40, 0.7);
+}
+
+.date-text {
+  flex: 1;
+}
+
+.calendar-icon {
+  font-size: 14px;
+  margin-left: 6px;
+}
+
+.date-picker-popup {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  margin-top: 8px;
+  background: rgba(0, 30, 60, 0.95);
+  border: 1px solid rgba(0, 212, 255, 0.3);
+  border-radius: 6px;
+  z-index: 100;
+  width: 100%;
+  box-shadow: 0 4px 12px rgba(0, 212, 255, 0.15);
+}
+
+.date-picker-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px 12px;
+  border-bottom: 1px solid rgba(0, 212, 255, 0.2);
+  color: #e0fcff;
+  font-size: 14px;
+  font-weight: bold;
+  gap: 8px;
+}
+
+.nav-btn {
+  background: none;
+  border: none;
+  color: #7bbef6;
+  font-size: 16px;
+  cursor: pointer;
+  padding: 4px 8px;
+  border-radius: 4px;
+  transition: all 0.3s ease;
+}
+
+.nav-btn:hover {
+  background: rgba(0, 212, 255, 0.2);
+  color: #e0fcff;
+}
+
+.current-month {
+  flex: 1;
+  text-align: center;
+}
+
+.close-btn {
+  background: none;
+  border: none;
+  color: #7bbef6;
+  font-size: 20px;
+  cursor: pointer;
+  padding: 0;
+  width: 24px;
+  height: 24px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.close-btn:hover {
+  color: #e0fcff;
+}
+
+.calendar-container {
+  padding: 12px;
+}
+
+.weekdays {
+  display: grid;
+  grid-template-columns: repeat(7, 1fr);
+  gap: 4px;
+  margin-bottom: 8px;
+}
+
+.weekday {
+  text-align: center;
+  color: #7bbef6;
+  font-size: 12px;
+  font-weight: bold;
+  padding: 4px;
+}
+
+.days {
+  display: grid;
+  grid-template-columns: repeat(7, 1fr);
+  gap: 4px;
+}
+
+.day {
+  text-align: center;
+  padding: 8px 4px;
+  font-size: 13px;
+  color: #e0fcff;
+  cursor: pointer;
+  border-radius: 4px;
+  transition: all 0.2s ease;
+  position: relative;
+}
+
+.day:hover:not(.empty) {
+  background: rgba(0, 212, 255, 0.2);
+}
+
+.day.empty {
+  cursor: default;
+  pointer-events: none;
+}
+
+.day.today {
+  color: #ffd93d;
+  font-weight: bold;
+}
+
+.day.in-range {
+  background: rgba(0, 212, 255, 0.15);
+  border-radius: 0;
+}
+
+.day.start {
+  background: rgba(0, 212, 255, 0.3);
+  border-radius: 4px 0 0 4px;
+  font-weight: bold;
+}
+
+.day.end {
+  background: rgba(0, 212, 255, 0.3);
+  border-radius: 0 4px 4px 0;
+  font-weight: bold;
+}
+
+.day.start.end {
+  border-radius: 4px;
+}
+
+.date-picker-footer {
+  padding: 10px 12px;
+  border-top: 1px solid rgba(0, 212, 255, 0.2);
+  display: flex;
+  justify-content: flex-end;
+}
+
+.confirm-btn {
+  padding: 8px 20px;
+  background: rgba(0, 212, 255, 0.2);
+  border: 1px solid rgba(0, 212, 255, 0.5);
+  border-radius: 4px;
+  color: #62f6fb;
+  font-size: 14px;
+  font-weight: bold;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.confirm-btn:hover {
+  background: rgba(0, 212, 255, 0.3);
+  color: #e0fcff;
+}
+
+.demand-cards {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.demand-cards-row {
+  display: flex;
+  gap: 8px;
+}
+
+.demand-card {
+  flex: 1;
+  padding: 8px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+  text-align: center;
+}
+
+.demand-card .card-label {
+  color: #7bbef6;
+  font-size: 11px;
+  margin-bottom: 6px;
+}
+
+.demand-card .card-value {
+  color: #e0fcff;
+  font-size: 15px;
+  font-weight: bold;
+  margin-bottom: 4px;
+}
+
+.demand-card .card-change {
+  font-size: 11px;
+  font-weight: bold;
+}
+
+.demand-card .card-change.up {
+  color: #ff6b6b;
+}
+
+.demand-card .card-change.down {
+  color: #4ade80;
+}
+
+.demand-card .card-value.surplus {
+  color: #4ade80;
+}
+
+.demand-card .card-value.deficit {
+  color: #ff6b6b;
+}
+
+.demand-card .card-status {
+  font-size: 11px;
+  font-weight: bold;
+}
+
+.demand-card .card-status.surplus {
+  color: #4ade80;
+}
+
+.demand-card .card-status.deficit {
+  color: #ff6b6b;
+}
+
+.demand-trend-card {
+  padding: 8px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.demand-trend-card .chart-label {
+  color: #e0fcff;
+  font-size: 14px;
+  font-weight: bold;
+  text-align: left;
+  margin-bottom: 6px;
+}
+
+.demand-trend-card .chart-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.demand-comparison-card {
+  padding: 8px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.demand-comparison-card .chart-label {
+  color: #e0fcff;
+  font-size: 14px;
+  font-weight: bold;
+  text-align: left;
+  margin-bottom: 6px;
+}
+
+.demand-comparison-card .chart-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
 </style>