hejianhao
2025-03-26 413e3b0b5c6dbc90cdf743a5ee1894a66a304963
修改配置
4个文件已修改
10个文件已删除
3个文件已添加
2440 ■■■■ 已修改文件
package.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 998 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/HelloWorld.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TheWelcome.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/WelcomeItem.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/icons/IconCommunity.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/icons/IconDocumentation.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/icons/IconEcosystem.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/icons/IconSupport.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/icons/IconTooling.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.js 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/AboutView.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/DataScreen.vue 1024 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/HomeView.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/service.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -8,15 +8,18 @@
  },
  "dependencies": {
    "@amap/amap-jsapi-loader": "^1.0.1",
    "axios": "^1.8.4",
    "dayjs": "^1.11.13",
    "echarts": "^5.6.0",
    "element-ui": "^2.15.14",
    "regenerator-runtime": "^0.14.1",
    "vue": "^2.7.7",
    "vue-router": "^3.5.4"
  },
  "devDependencies": {
    "@vitejs/plugin-legacy": "^2.0.0",
    "@vitejs/plugin-legacy": "^2.3.1",
    "@vitejs/plugin-vue2": "^1.1.2",
    "terser": "^5.14.2",
    "vite": "^3.0.2"
    "terser": "^5.4.0",
    "vite": "^3.0.0"
  }
}
src/App.vue
@@ -1,1005 +1,23 @@
<script>
import AMapLoader from '@amap/amap-jsapi-loader'
import * as echarts from 'echarts'
import dayjs from 'dayjs'
<template>
  <div id="app">
    <router-view />
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      map: null,
      markers: [],
      infoWindow: null,
      currentTime: '',
      currentDate: '',
      temperature: '--',
      totalArea: '386.5',
      rentedArea: '316.5',
      todayRent: '316.5',
      todayIncome: '124.5',
      newUsers: '877',
      quarterlyRate: '4302',
      weather: null,
      rentList: [
        { area: '新城大道', status: 'online' },
        { area: '拉萨路', status: 'offline' },
        { area: '新城大道', status: 'online' },
        { area: '拉萨路', status: 'online' },
        { area: '新城大道', status: 'offline' },
        { area: '拉萨路', status: 'online' },
        { area: '新城大道', status: 'offline' },
        { area: '新城大道', status: 'online' }
      ],
      charts: {
        areaRent: null,
        income: null,
        rentTrend: null
      }
    }
  },
  mounted() {
    this.initMap()
    this.initCharts()
    this.startTimeUpdate()
    this.startWeatherUpdate()
  },
  methods: {
    startTimeUpdate() {
      const updateTime = () => {
        this.currentTime = dayjs().format('HH:mm:ss')
        this.currentDate = dayjs().format('YYYY/MM/DD')
      }
      updateTime()
      setInterval(updateTime, 1000)
    },
    startWeatherUpdate() {
      const updateWeather = async () => {
        try {
          // 使用 OpenMeteo API
          const response = await fetch('https://api.open-meteo.com/v1/forecast?latitude=29.6487&longitude=91.1172&current=temperature_2m&timezone=Asia%2FShanghai')
          const data = await response.json()
          if (data.current) {
            this.temperature = Math.round(data.current.temperature_2m)
          }
        } catch (error) {
          console.error('获取天气数据失败:', error)
        }
      }
      // 立即更新一次
      updateWeather()
      // 每30分钟更新一次
      setInterval(updateWeather, 30 * 60 * 1000)
    },
    async initMap() {
      try {
        const AMap = await AMapLoader.load({
          key: '526e04b30ceba8f217c5def5a92392f9',
          version: '2.0',
          plugins: ['AMap.ToolBar', 'AMap.Scale']
        })
        this.map = new AMap.Map(this.$refs.mapContainer, {
          zoom: 16,
          center: [91.1172, 29.6487],
          viewMode: '3D',
          pitch: 35,
          mapStyle: 'amap://styles/normal',
          features: ['bg', 'road', 'building', 'point'],
          buildingAnimation: true
        })
        this.map.addControl(new AMap.ToolBar({
          position: 'RB'
        }))
        this.map.addControl(new AMap.Scale({
          position: 'RB'
        }))
        // 创建信息窗口
        this.infoWindow = new AMap.InfoWindow({
          offset: new AMap.Pixel(0, -30),
          closeWhenClickMap: true,
          autoMove: true,
          anchor: 'bottom-center'
        })
        // 添加地图点击事件
        this.map.on('click', () => {
          if (this.infoWindow) {
            this.infoWindow.close()
          }
        })
        this.addMarkers()
      } catch (error) {
        console.error('地图加载失败:', error)
      }
    },
    addMarkers() {
      const houses = [
        {
          position: [91.1172, 29.6487],
          title: '新城大道房源',
          status: 'waiting',
          content: `
            <div class="info-window" data-status="waiting">
              <div class="info-title">房屋状态:待租出</div>
              <div class="info-content">
                <p>房屋编号:新城大道</p>
                <p>房屋状态:待租出</p>
                <p>租赁面积:1000/2000㎡</p>
                <p>本季租金:500/2000元/月</p>
              </div>
            </div>
          `
        },
        {
          position: [91.1272, 29.6587],
          title: '拉萨路房源',
          status: 'rented',
          content: `
            <div class="info-window" data-status="rented">
              <div class="info-title">房屋状态:已租出</div>
              <div class="info-content">
                <p>房屋编号:拉萨路</p>
                <p>房屋状态:已租出</p>
                <p>租赁面积:800/1500㎡</p>
                <p>本季租金:400/1800元/月</p>
              </div>
            </div>
          `
        }
      ]
      houses.forEach(house => {
        // 创建多层圆环
        const circles = []
        const baseRadius = 15
        const numCircles = 3
        // 创建中心点
        const centerCircle = new AMap.Circle({
          center: house.position,
          radius: baseRadius / 2,
          fillColor: house.status === 'waiting' ? '#ff9800' : '#4CAF50',
          fillOpacity: 0.8,
          strokeWeight: 0,
          zIndex: numCircles + 2,
          bubble: true,
          cursor: 'pointer'
        })
        // 创建多层圆环
        for (let i = 0; i < numCircles; i++) {
          circles.push(new AMap.Circle({
            center: house.position,
            radius: baseRadius * (i + 1),
            fillColor: house.status === 'waiting' ? '#ff9800' : '#4CAF50',
            fillOpacity: 0.3 - (i * 0.05),
            strokeColor: house.status === 'waiting' ? '#ff9800' : '#4CAF50',
            strokeWeight: 2,
            strokeOpacity: 0.5 - (i * 0.08),
            zIndex: numCircles - i,
            bubble: true,
            cursor: 'pointer'
          }))
        }
        // 点击事件处理
        const clickHandler = () => {
          if (this.infoWindow) {
            this.infoWindow.setContent(house.content)
            this.infoWindow.open(this.map, house.position)
          }
        }
        // 为所有圆环添加点击事件
        centerCircle.on('click', clickHandler)
        circles.forEach(circle => circle.on('click', clickHandler))
        // 添加到地图
        this.map.add([centerCircle, ...circles])
        this.markers.push({ center: centerCircle, rings: circles })
        // 动画效果
        let phase = 0
        const animate = () => {
          phase += 0.15
          const scale = 1 + 0.6 * Math.sin(phase)
          circles.forEach((circle, index) => {
            const currentRadius = baseRadius * (index + 1)
            circle.setRadius(currentRadius * scale)
            const baseOpacity = 0.3 - (index * 0.05)
            const opacityScale = 1 + 0.5 * Math.sin(phase)
            circle.setOptions({
              fillOpacity: baseOpacity * opacityScale,
              strokeOpacity: (0.5 - (index * 0.08)) * opacityScale
            })
          })
          requestAnimationFrame(animate)
        }
        animate()
      })
    },
    initCharts() {
      // 区域租金分析图表
      this.charts.areaRent = echarts.init(this.$refs.areaRentChart)
      this.charts.areaRent.setOption({
        grid: {
          left: '20%',
          right: '5%',
          top: '10%',
          bottom: '10%'
        },
        xAxis: {
          type: 'value',
          axisLine: {
            show: false
          },
          splitLine: {
            show: false
          },
          axisLabel: {
            color: '#fff'
          }
        },
        yAxis: {
          type: 'category',
          data: ['新城大道', '拉萨路', '新城大道', '拉萨路', '新城大道', '新城大道', '拉萨路', '新城大道', '拉萨路', '新城大道'],
          axisLine: {
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        series: [{
          type: 'bar',
          data: [1900, 1850, 1800, 1750, 1700, 1600, 1500, 1400, 1300, 1200, 1100, 1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 0],
          barWidth: '30%',
          itemStyle: {
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 1,
              y2: 0,
              colorStops: [{
                offset: 0,
                color: '#0ff'
              }, {
                offset: 1,
                color: '#0ff'
              }]
            }
          }
        }]
      })
      // 收入趋势图表
      this.charts.income = echarts.init(this.$refs.incomeChart)
      this.charts.income.setOption({
        grid: {
          top: '15%',
          left: '3%',
          right: '3%',
          bottom: '3%',
          containLabel: true
        },
        tooltip: {
          trigger: 'axis'
        },
        xAxis: {
          type: 'category',
          data: ['23-4月', '23-12月', '24-3月', '24-4月', '24-5月', '24-6月', '25-3月'],
          axisLine: {
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        yAxis: {
          type: 'value',
          splitLine: {
            show: false
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        series: [{
          data: [100, 400, 200, 300, 200, 400, 300],
          type: 'line',
          smooth: true,
          symbol: 'circle',
          symbolSize: 8,
          lineStyle: {
            color: '#ffd700',
            width: 2
          },
          itemStyle: {
            color: '#ffd700'
          },
          areaStyle: {
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 0,
              y2: 1,
              colorStops: [{
                offset: 0,
                color: 'rgba(255, 215, 0, 0.3)'
              }, {
                offset: 1,
                color: 'rgba(255, 215, 0, 0.1)'
              }]
            }
          }
        }]
      })
      // 租金趋势图表
      this.charts.rentTrend = echarts.init(this.$refs.rentTrendChart)
      this.charts.rentTrend.setOption({
        grid: {
          top: '15%',
          left: '3%',
          right: '3%',
          bottom: '3%',
          containLabel: true
        },
        tooltip: {
          trigger: 'axis'
        },
        xAxis: {
          type: 'category',
          data: ['23-4月', '23-12月', '24-3月', '24-4月', '24-5月', '24-6月', '25-3月'],
          axisLine: {
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        yAxis: {
          type: 'value',
          splitLine: {
            show: false
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        series: [{
          data: [300, 200, 400, 300, 500, 400, 300],
          type: 'line',
          smooth: true,
          symbol: 'circle',
          symbolSize: 8,
          lineStyle: {
            color: '#4facfe',
            width: 2
          },
          itemStyle: {
            color: '#4facfe'
          },
          areaStyle: {
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 0,
              y2: 1,
              colorStops: [{
                offset: 0,
                color: 'rgba(79,172,254,0.3)'
              }, {
                offset: 1,
                color: 'rgba(79,172,254,0.1)'
              }]
            }
          }
        }]
      })
      // 监听窗口大小变化
      window.addEventListener('resize', () => {
        Object.values(this.charts).forEach(chart => {
          chart && chart.resize()
        })
      })
    }
  }
}
</script>
<template>
  <div id="app">
    <div class="header">
      <div class="time-weather">
            <span class="time">{{ currentTime }}</span>
            <span class="date">{{ currentDate }}</span>
            <span class="weather">
              <i class="weather-icon"></i>
              {{ temperature }}°C
            </span>
          </div>
    </div>
    <div class="main-content">
      <div class="left-panel">
        <div class="header-center">
          <div class="title">西藏国投租金系统数据看板</div>
          <div class="sub-title">Ecological simulation display in business district</div>
        </div>
        <div class="header-left" style="width: 350px;">
          <div class="stat-group">
            <div class="stat-item">
              <div class="stat-info">
                <div class="stat-label"> <i class="icon-area"></i> 房屋总面积</div>
                <div class="stat-value">{{ totalArea }}<span class="unit">m²</span></div>
              </div>
            </div>
            <div class="stat-item">
              <div class="stat-info">
                <div class="stat-label">  <i class="icon-area"></i>已出租面积</div>
                <div class="stat-value">{{ rentedArea }}<span class="unit">m²</span></div>
              </div>
            </div>
          </div>
          <div class="header-right">
            <div class="stat-group">
              <div class="stat-item  mt-10">
                <div class="stat-info">
                  <div class="stat-label"> <i class="icon-money"></i>今日已收租金</div>
                  <div class="stat-value">{{ todayRent }}<span class="unit">万元</span></div>
                </div>
              </div>
              <div class="stat-item mt-10">
                <div class="stat-info">
                  <div class="stat-label"><i class="icon-money"></i>今日已收租金</div>
                  <div class="stat-value">{{ todayIncome }}<span class="unit">万元</span></div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="chart-card" style="width: 350px;">
          <div class="chart-title">区域租金分析</div>
          <div class="area-chart" ref="areaRentChart"></div>
        </div>
        <div class="bottom-charts">
          <div class="bottom-charts">
            <div class="chart-group">
              <div class="chart-title">收入趋势</div>
              <div class="income-chart" ref="incomeChart"></div>
            </div>
            <div class="chart-group">
              <div class="chart-title">租金收入趋势图</div>
              <div class="trend-chart" ref="rentTrendChart"></div>
            </div>
          </div>
        </div>
      </div>
      <div class="center-panel">
        <div class="map-container" ref="mapContainer"></div>
      </div>
      <div class="right-panel">
        <div class="right-panel-top">
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本月新增用户</div>
              <div class="data-tabs">
                <div class="tab-value">{{ newUsers }}<span class="unit">户</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本季度交租率</div>
              <div class="data-tabs">
                <div class="tab-value">{{ quarterlyRate }}<span class="unit">元</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
        </div>
        <div class="right-panel-top1">
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本月新增用户</div>
              <div class="data-tabs">
                <div class="tab-value">{{ newUsers }}<span class="unit">万元</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本季度交租率</div>
              <div class="data-tabs">
                <div class="tab-value">{{ quarterlyRate }}<span class="unit">万元</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
        </div>
        <div class="status-list">
          <div class="status-title">实时租赁数据</div>
          <div class="status-items-container">
          <div class="status-items">
            <div v-for="(item, index) in [...rentList, ...rentList]" :key="index" class="status-item">
              <span class="area-name">{{ item.area }}</span>
              <div class="status-actions">
                <span class="action-btn">启用中</span>
                <span class="action-btn">合同签署</span>
              </div>
            </div>
          </div>
        </div>
        </div>
      </div>
    </div>
    <div class="footer"></div>
  </div>
</template>
<style>
.flex{
  display: flex;
  flex-direction: column;
}
#app {
  width: 100vw;
  height: 100vh;
  margin: 0;
  padding: 0;
  padding: 0 !important;
  overflow: hidden;
  background: linear-gradient(to bottom, #1a2b3c 0%, rgba(26, 43, 60, 0.8) 20%, rgba(26, 43, 60, 0) 100%);
  color: #fff;
  font-family: 'DIN ', 'DIN', sans-serif;
  display: flex;
  flex-direction: column;
}
/* 添加全局字体声明 */
@font-face {
  font-family: 'DIN';
  src: url('https://fonts.cdnfonts.com/css/din-next-lt-arabic') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}
.header {
  height: 120px;
  display: flex;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  background: linear-gradient(to bottom, rgba(1, 85, 121, 0.8) 0%, rgba(1, 85, 121, 0.4) 40%, rgba(151, 190, 192, 0) 100%);
  z-index: 1000;
  justify-content: flex-end;
  align-items: center;
  padding: 10px 20px;
  /* background: rgba(255, 255, 255, 0.05); */
  backdrop-filter: blur(10px);
}
.footer {
  height: 200px;
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100vw;
  z-index: 1000;
  background: linear-gradient(to top, rgba(1, 85, 121, 0.8) 0%, rgba(1, 85, 121, 0.4) 20%, rgba(151, 190, 192, 0) 100%);
}
.header-left,
.header-right {
  /* width: 30%; */
}
.header-center {
  /* text-align: center; */
  margin-left: 20px;
  margin-top: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid #8CB4C6;
}
.title {
  font-size: 30px;
  font-weight: bold;
  background: linear-gradient(90deg, #fff, #0ff);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  /* margin-bottom: 10px; */
}
.sub-title {
  font-size: 12px;
  color: fff;
}
.time-weather {
  display: flex;
  gap: 20px;
  align-items: center;
  /* justify-content: center; */
}
.time {
  font-size: 24px;
  font-weight: bold;
}
.date {
  color: #fff;
}
.weather {
  display: flex;
  align-items: center;
  gap: 5px;
}
.main-content {
  flex: 1;
  display: flex;
  /* padding: 10px; */
  gap: 10px;
}
.left-panel {
  width: 400px;
  display: flex;
  position: fixed;
  top: 0;
  left: 0;
  height: calc(100vh);
  background: linear-gradient(to right, rgba(1, 85, 121, 0.8) 0%, rgba(1, 85, 121, 0.8) 20%, rgba(151, 190, 192, 0));
  /* margin-top: 100px; */
  /* padding-top: 10px; */
  z-index: 1002;
  flex-direction: column;
  padding-bottom: 200px;
  gap: 10px;
}
.bottom-charts {
  height: 200px;
  width: 700px;
  position: fixed;
  bottom: 0;
  left: 0;
  z-index: 1000;
  /* background: linear-gradient(to right, rgba(1, 85, 121, 0.1) 0%, rgba(1, 85, 121, 0.1) 50%, rgba(151, 190, 192, 0) 100%); */
}
.right-panel {
  width: 300px;
  display: flex;
  position: fixed;
  top: 0;
  right: 0;
  height: calc(100vh - 100px);
  margin-top: 100px;
  z-index: 1000;
  flex-direction: column;
  gap: 10px;
}
.center-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.map-container {
  flex: 1;
  border-radius: 8px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.05);
}
.bottom-charts {
  /* height: 200px; */
  display: flex;
  gap: 10px;
  /* margin-bottom: 40px; */
}
.stat-group {
  display: flex;
  gap: 10px;
}
.stat-item {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.icon-area,
.icon-money {
  width: 40px;
  height: 40px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 50%;
}
.stat-info {
  flex: 1;
}
.mt-10{
  margin-top: 10px;
}
.stat-label {
  font-size: 14px;
  color: #fff;
  margin-bottom: 5px;
}
.stat-value {
  font-size: 24px;
  font-weight: bold;
  color: #0ff;
}
.unit {
  font-size: 14px;
  margin-left: 4px;
  color: #fff;
}
.chart-card {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 15px;
  min-height: 300px;
}
.chart-title {
  font-size: 16px;
  margin-bottom: 15px;
  color: #fff;
}
.area-chart {
  height: calc(100% - 30px);
}
.data-card {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 15px;
  height: 80px;
}
.data-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.data-title {
  font-size: 16px;
}
.data-tabs {
  display: flex;
  align-items: center;
  gap: 10px;
}
.tab-value {
  font-size: 30px;
  font-family: 'DIN ', 'DIN', sans-serif;
  font-weight: bold;
  color: #fff;
  /* font-family: "DINPro-Bold"; */
}
.status-list {
  background: rgba(146, 146, 146,0.5);
  border-radius: 2px;
  margin-right: 20px;
  margin-top: 10px;
  padding: 15px;
  height: 500px;
  overflow: hidden;
}
.status-title {
  font-size: 16px;
  /* margin-bottom: 15px; */
}
.status-items {
  display: flex;
  flex-direction: column;
  gap: 10px;
  height: calc(100% - 45px);
  animation: scrollUp 20s linear infinite;
}
.status-items:hover {
  animation-play-state: paused;
}
.status-items-container{
  height: 100%;
  overflow: hidden;
}
@keyframes scrollUp {
  0% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(-50%);
  }
}
/* 隐藏滚动条 */
.status-items::-webkit-scrollbar {
  display: none;
}
.status-items {
  -ms-overflow-style: none;
  scrollbar-width: none;
}
.status-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* padding: 10px; */
  background: rgba(255, 255, 255, 0.05);
  border-radius: 4px;
}
.area-name {
  font-size: 12px;
}
.status-actions {
  display: flex;
  gap: 10px;
}
.action-btn {
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
  background: rgba(0, 255, 255, 0.2);
}
.chart-group {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 10px;
}
.income-chart,
.trend-chart {
  height: calc(100% - 30px);
}
.info-window {
  padding: 10px;
  background: rgba(146, 146, 146, 0.5);
  border-radius: 8px;
  z-index: 10003;
  min-width: 200px;
}
.info-title {
  font-size: 16px;
  font-weight: bold;
  color: #fff;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid #eee;
}
.info-content {
  font-size: 12px;
  color: #fff;
}
.info-content p {
  margin: 8px 0;
  line-height: 1.4;
}
.info-window[data-status="waiting"] .info-title {
  color: #fff;
}
.info-window[data-status="rented"] .info-title {
  color: #fff;
}
.amap-info {
  z-index: 10003 !important;
  display: block !important;
}
.amap-info-content {
  background: rgba(146, 146, 146, 0.5);
  padding: 0 !important;
}
.amap-info-sharp {
  display: none !important;
}
.right-panel-top{
  display: flex;
  background: rgba(146, 146, 146,0.5);
  margin-top: 50px;
  padding-top: 10px;
  padding-bottom: 30px;
  border-radius: 2px;
  margin-right: 20px;
  border-left: 4px solid #87F7C7;
  /* height: 100px; */
}
.right-panel-top1{
  display: flex;
  background: rgba(146, 146, 146,0.5);
  margin-top: 10px;
  padding-top: 10px;
  padding-bottom: 30px;
  border-radius: 2px;
  margin-right: 20px;
  border-left: 4px solid #FFB822;
  /* height: 100px; */
}
</style>
</style>
src/components/HelloWorld.vue
File was deleted
src/components/TheWelcome.vue
File was deleted
src/components/WelcomeItem.vue
File was deleted
src/components/icons/IconCommunity.vue
File was deleted
src/components/icons/IconDocumentation.vue
File was deleted
src/components/icons/IconEcosystem.vue
File was deleted
src/components/icons/IconSupport.vue
File was deleted
src/components/icons/IconTooling.vue
File was deleted
src/router/index.js
@@ -1,6 +1,6 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import DataScreen from '../views/DataScreen.vue'
Vue.use(VueRouter)
@@ -10,17 +10,9 @@
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
      name: 'DataScreen',
      component: DataScreen
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/AboutView.vue')
    }
  ]
})
src/utils/request.js
New file
@@ -0,0 +1,81 @@
import axios from 'axios'
import {
  Message
} from 'element-ui'
const service = axios.create({
  baseURL: '/',  // 使用相对路径,让代理生效
  withCredentials: false, // 当跨域请求时发送cookie
  timeout: 30000, // request timeout
})
// 请求拦截
service.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      // 添加token到请求头
      config.headers['Authorization'] = token
    }
    if (config.method == 'get') {
      if (!config.params) config.params = {};
      config.params = {
        ...config.params,
      }
    }
    if (config.method == 'post') {
      if (!config.data) config.data = {};
      config.data = {
        ...config.data,
      }
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)
// 响应拦截
service.interceptors.response.use(
  response => {
    if (!response) {
      return Promise.reject(new Error('请求超时'))
    }
    const res = response;
    if (res.status === 200) {
      if (!res.data) {
        EditionPayDialog({
          show: true
        });
        return Promise.reject(new Error('暂无数据'))
      }
      if (res.data.code == 500) {
        Message({
          message: res.data.message || 'Error',
          type: 'error',
          duration: 3000
        })
        return Promise.reject(new Error(res.data.message))
      }
      return res.data
    } else {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 3000
      })
      return Promise.reject(new Error(res.message || 'Error'))
    }
  },
  error => {
    console.log('err' + error)
    Message({
      message: error.message,
      type: 'error',
      duration: 5000
    })
    return Promise.reject(error)
  }
)
export default service
src/views/AboutView.vue
File was deleted
src/views/DataScreen.vue
New file
@@ -0,0 +1,1024 @@
<template>
  <div id="app">
    <div class="header">
      <div class="time-weather">
        <span class="time">{{ currentTime }}</span>
        <span class="date">{{ currentDate }}</span>
        <span class="weather">
          <i class="weather-icon"></i>
          {{ temperature }}°C
        </span>
      </div>
    </div>
    <div class="main-content">
      <div class="left-panel">
        <div class="header-center">
          <div class="title">西藏国投租金系统数据看板</div>
          <div class="sub-title">Ecological simulation display in business district</div>
        </div>
        <div class="header-left" style="width: 350px;">
          <div class="stat-group">
            <div class="stat-item">
              <div class="stat-info">
                <div class="stat-label"> <i class="icon-area"></i> 房屋总面积</div>
                <div class="stat-value">{{ totalArea }}<span class="unit">m²</span></div>
              </div>
            </div>
            <div class="stat-item">
              <div class="stat-info">
                <div class="stat-label"> <i class="icon-area"></i>已出租面积</div>
                <div class="stat-value">{{ rentedArea }}<span class="unit">m²</span></div>
              </div>
            </div>
          </div>
          <div class="header-right">
            <div class="stat-group">
              <div class="stat-item  mt-10">
                <div class="stat-info">
                  <div class="stat-label"> <i class="icon-money"></i>今日已收租金</div>
                  <div class="stat-value">{{ todayRent }}<span class="unit">万元</span></div>
                </div>
              </div>
              <div class="stat-item mt-10">
                <div class="stat-info">
                  <div class="stat-label"><i class="icon-money"></i>今日已收租金</div>
                  <div class="stat-value">{{ todayIncome }}<span class="unit">万元</span></div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="chart-card" style="width: 350px;">
          <div class="chart-title">区域租金分析</div>
          <div class="area-chart" ref="areaRentChart"></div>
        </div>
        <div class="bottom-charts">
          <div class="bottom-charts">
            <div class="chart-group">
              <div class="chart-title">收入趋势</div>
              <div class="income-chart" ref="incomeChart"></div>
            </div>
            <div class="chart-group">
              <div class="chart-title">租金收入趋势图</div>
              <div class="trend-chart" ref="rentTrendChart"></div>
            </div>
          </div>
        </div>
      </div>
      <div class="center-panel">
        <div class="map-container" ref="mapContainer"></div>
      </div>
      <div class="right-panel">
        <div class="right-panel-top">
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本月新增用户</div>
              <div class="data-tabs">
                <div class="tab-value">{{ newUsers }}<span class="unit">户</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本季度交租率</div>
              <div class="data-tabs">
                <div class="tab-value">{{ quarterlyRate }}<span class="unit">元</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
        </div>
        <div class="right-panel-top1">
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本月新增用户</div>
              <div class="data-tabs">
                <div class="tab-value">{{ newUsers }}<span class="unit">万元</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
          <div class="data-card">
            <div class="data-header flex">
              <div class="data-title">本季度交租率</div>
              <div class="data-tabs">
                <div class="tab-value">{{ quarterlyRate }}<span class="unit">万元</span></div>
                <div class="tab-chart"></div>
              </div>
            </div>
          </div>
        </div>
        <div class="status-list">
          <div class="status-title">实时租赁数据</div>
          <div class="status-items-container">
            <div class="status-items">
              <div v-for="(item, index) in rentList" :key="index" class="status-item">
                <span class="area-name">{{ item.area }}</span>
                <div class="status-actions">
                  <span class="action-btn">启用中</span>
                  <span class="action-btn">合同签署</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="footer"></div>
  </div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader'
import * as echarts from 'echarts'
import dayjs from 'dayjs'
import { getData } from './service'
export default {
  name: 'DataScreen',
  data() {
    return {
      map: null,
      markers: [],
      infoWindow: null,
      currentTime: '',
      currentDate: '',
      temperature: '--',
      totalArea: '386.5',
      rentedArea: '316.5',
      todayRent: '316.5',
      todayIncome: '124.5',
      newUsers: '877',
      quarterlyRate: '4302',
      weather: null,
      rentList: [
        { area: '新城大道', status: 'online' },
        { area: '拉萨路', status: 'offline' },
        { area: '新城大道', status: 'online' },
        { area: '拉萨路', status: 'online' },
        { area: '新城大道', status: 'offline' },
        { area: '拉萨路', status: 'online' },
        { area: '新城大道', status: 'offline' },
        { area: '新城大道', status: 'online' }
      ],
      charts: {
        areaRent: null,
        income: null,
        rentTrend: null
      }
    }
  },
  created() {
    console.log(this.$route);
    if (this.$route.query.token || localStorage.getItem('token')) {
      localStorage.setItem('token', 'Bearer ' + this.$route.query.token)
      this.fetchData()
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initMap()
      this.initCharts()
    })
    this.startTimeUpdate()
    this.startWeatherUpdate()
  },
  methods: {
    fetchData() {
      getData().then(res => {
        console.log(res)
      })
    },
    startTimeUpdate() {
      const updateTime = () => {
        this.currentTime = dayjs().format('HH:mm:ss')
        this.currentDate = dayjs().format('YYYY/MM/DD')
      }
      updateTime()
      setInterval(updateTime, 1000)
    },
    startWeatherUpdate() {
      const updateWeather = async () => {
        try {
          // 使用 OpenMeteo API
          const response = await fetch('https://api.open-meteo.com/v1/forecast?latitude=29.6487&longitude=91.1172&current=temperature_2m&timezone=Asia%2FShanghai')
          const data = await response.json()
          if (data.current) {
            this.temperature = Math.round(data.current.temperature_2m)
          }
        } catch (error) {
          console.error('获取天气数据失败:', error)
        }
      }
      // 立即更新一次
      updateWeather()
      // 每30分钟更新一次
      setInterval(updateWeather, 30 * 60 * 1000)
    },
    async initMap() {
      try {
        const AMap = await AMapLoader.load({
          key: '526e04b30ceba8f217c5def5a92392f9',
          version: '2.0',
          plugins: ['AMap.ToolBar', 'AMap.Scale']
        })
        this.map = new AMap.Map(this.$refs.mapContainer, {
          zoom: 16,
          center: [91.1172, 29.6487],
          viewMode: '3D',
          pitch: 35,
          mapStyle: 'amap://styles/normal',
          features: ['bg', 'road', 'building', 'point'],
          buildingAnimation: true
        })
        this.map.addControl(new AMap.ToolBar({
          position: 'RB'
        }))
        this.map.addControl(new AMap.Scale({
          position: 'RB'
        }))
        // 创建信息窗口
        this.infoWindow = new AMap.InfoWindow({
          offset: new AMap.Pixel(0, -30),
          closeWhenClickMap: true,
          autoMove: true,
          anchor: 'bottom-center'
        })
        // 添加地图点击事件
        this.map.on('click', () => {
          if (this.infoWindow) {
            this.infoWindow.close()
          }
        })
        this.addMarkers()
      } catch (error) {
        console.error('地图加载失败:', error)
      }
    },
    addMarkers() {
      const houses = [
        {
          position: [91.1172, 29.6487],
          title: '新城大道房源',
          status: 'waiting',
          content: `
            <div class="info-window" data-status="waiting">
              <div class="info-title">房屋状态:待租出</div>
              <div class="info-content">
                <p>房屋编号:新城大道</p>
                <p>房屋状态:待租出</p>
                <p>租赁面积:1000/2000㎡</p>
                <p>本季租金:500/2000元/月</p>
              </div>
            </div>
          `
        },
        {
          position: [91.1272, 29.6587],
          title: '拉萨路房源',
          status: 'rented',
          content: `
            <div class="info-window" data-status="rented">
              <div class="info-title">房屋状态:已租出</div>
              <div class="info-content">
                <p>房屋编号:拉萨路</p>
                <p>房屋状态:已租出</p>
                <p>租赁面积:800/1500㎡</p>
                <p>本季租金:400/1800元/月</p>
              </div>
            </div>
          `
        }
      ]
      houses.forEach(house => {
        // 创建多层圆环
        const circles = []
        const baseRadius = 15
        const numCircles = 3
        // 创建中心点
        const centerCircle = new AMap.Circle({
          center: house.position,
          radius: baseRadius / 2,
          fillColor: house.status === 'waiting' ? '#ff9800' : '#4CAF50',
          fillOpacity: 0.8,
          strokeWeight: 0,
          zIndex: numCircles + 2,
          bubble: true,
          cursor: 'pointer'
        })
        // 创建多层圆环
        for (let i = 0; i < numCircles; i++) {
          circles.push(new AMap.Circle({
            center: house.position,
            radius: baseRadius * (i + 1),
            fillColor: house.status === 'waiting' ? '#ff9800' : '#4CAF50',
            fillOpacity: 0.3 - (i * 0.05),
            strokeColor: house.status === 'waiting' ? '#ff9800' : '#4CAF50',
            strokeWeight: 2,
            strokeOpacity: 0.5 - (i * 0.08),
            zIndex: numCircles - i,
            bubble: true,
            cursor: 'pointer'
          }))
        }
        // 点击事件处理
        const clickHandler = () => {
          if (this.infoWindow) {
            this.infoWindow.setContent(house.content)
            this.infoWindow.open(this.map, house.position)
          }
        }
        // 为所有圆环添加点击事件
        centerCircle.on('click', clickHandler)
        circles.forEach(circle => circle.on('click', clickHandler))
        // 添加到地图
        this.map.add([centerCircle, ...circles])
        this.markers.push({ center: centerCircle, rings: circles })
        // 动画效果
        let phase = 0
        const animate = () => {
          phase += 0.15
          const scale = 1 + 0.6 * Math.sin(phase)
          circles.forEach((circle, index) => {
            const currentRadius = baseRadius * (index + 1)
            circle.setRadius(currentRadius * scale)
            const baseOpacity = 0.3 - (index * 0.05)
            const opacityScale = 1 + 0.5 * Math.sin(phase)
            circle.setOptions({
              fillOpacity: baseOpacity * opacityScale,
              strokeOpacity: (0.5 - (index * 0.08)) * opacityScale
            })
          })
          requestAnimationFrame(animate)
        }
        animate()
      })
    },
    initCharts() {
      // 区域租金分析图表
      this.charts.areaRent = echarts.init(this.$refs.areaRentChart)
      this.charts.areaRent.setOption({
        grid: {
          left: '20%',
          right: '5%',
          top: '10%',
          bottom: '10%'
        },
        xAxis: {
          type: 'value',
          axisLine: {
            show: false
          },
          splitLine: {
            show: false
          },
          axisLabel: {
            color: '#fff'
          }
        },
        yAxis: {
          type: 'category',
          data: ['新城大道', '拉萨路', '新城大道', '拉萨路', '新城大道', '新城大道', '拉萨路', '新城大道', '拉萨路', '新城大道'],
          axisLine: {
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        series: [{
          type: 'bar',
          data: [1900, 1850, 1800, 1750, 1700, 1600, 1500, 1400, 1300, 1200, 1100, 1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 0],
          barWidth: '30%',
          itemStyle: {
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 1,
              y2: 0,
              colorStops: [{
                offset: 0,
                color: '#0ff'
              }, {
                offset: 1,
                color: '#0ff'
              }]
            }
          }
        }]
      })
      // 收入趋势图表
      this.charts.income = echarts.init(this.$refs.incomeChart)
      this.charts.income.setOption({
        grid: {
          top: '15%',
          left: '3%',
          right: '3%',
          bottom: '3%',
          containLabel: true
        },
        tooltip: {
          trigger: 'axis'
        },
        xAxis: {
          type: 'category',
          data: ['23-4月', '23-12月', '24-3月', '24-4月', '24-5月', '24-6月', '25-3月'],
          axisLine: {
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        yAxis: {
          type: 'value',
          splitLine: {
            show: false
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        series: [{
          data: [100, 400, 200, 300, 200, 400, 300],
          type: 'line',
          smooth: true,
          symbol: 'circle',
          symbolSize: 8,
          lineStyle: {
            color: '#ffd700',
            width: 2
          },
          itemStyle: {
            color: '#ffd700'
          },
          areaStyle: {
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 0,
              y2: 1,
              colorStops: [{
                offset: 0,
                color: 'rgba(255, 215, 0, 0.3)'
              }, {
                offset: 1,
                color: 'rgba(255, 215, 0, 0.1)'
              }]
            }
          }
        }]
      })
      // 租金趋势图表
      this.charts.rentTrend = echarts.init(this.$refs.rentTrendChart)
      this.charts.rentTrend.setOption({
        grid: {
          top: '15%',
          left: '3%',
          right: '3%',
          bottom: '3%',
          containLabel: true
        },
        tooltip: {
          trigger: 'axis'
        },
        xAxis: {
          type: 'category',
          data: ['23-4月', '23-12月', '24-3月', '24-4月', '24-5月', '24-6月', '25-3月'],
          axisLine: {
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        yAxis: {
          type: 'value',
          splitLine: {
            show: false
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            color: '#fff'
          }
        },
        series: [{
          data: [300, 200, 400, 300, 500, 400, 300],
          type: 'line',
          smooth: true,
          symbol: 'circle',
          symbolSize: 8,
          lineStyle: {
            color: '#4facfe',
            width: 2
          },
          itemStyle: {
            color: '#4facfe'
          },
          areaStyle: {
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 0,
              y2: 1,
              colorStops: [{
                offset: 0,
                color: 'rgba(79,172,254,0.3)'
              }, {
                offset: 1,
                color: 'rgba(79,172,254,0.1)'
              }]
            }
          }
        }]
      })
      // 监听窗口大小变化
      window.addEventListener('resize', () => {
        Object.values(this.charts).forEach(chart => {
          chart && chart.resize()
        })
      })
    }
  }
}
</script>
<style>
.flex {
  display: flex;
  flex-direction: column;
}
#app {
  width: 100vw;
  height: 100vh;
  margin: 0;
  padding: 0;
  padding: 0 !important;
  overflow: hidden;
  background: linear-gradient(to bottom, #1a2b3c 0%, rgba(26, 43, 60, 0.8) 20%, rgba(26, 43, 60, 0) 100%);
  color: #fff;
  font-family: 'DIN ', 'DIN', sans-serif;
  display: flex;
  flex-direction: column;
}
/* 添加全局字体声明 */
@font-face {
  font-family: 'DIN';
  src: url('https://fonts.cdnfonts.com/css/din-next-lt-arabic') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}
.header {
  height: 120px;
  display: flex;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  background: linear-gradient(to bottom, rgba(1, 85, 121, 0.8) 0%, rgba(1, 85, 121, 0.4) 40%, rgba(151, 190, 192, 0) 100%);
  z-index: 1000;
  justify-content: flex-end;
  align-items: center;
  padding: 10px 20px;
  /* background: rgba(255, 255, 255, 0.05); */
  backdrop-filter: blur(10px);
}
.footer {
  height: 200px;
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100vw;
  z-index: 1000;
  background: linear-gradient(to top, rgba(1, 85, 121, 0.8) 0%, rgba(1, 85, 121, 0.4) 20%, rgba(151, 190, 192, 0) 100%);
}
.header-left,
.header-right {
  /* width: 30%; */
}
.header-center {
  /* text-align: center; */
  margin-left: 20px;
  margin-top: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid #8CB4C6;
}
.title {
  font-size: 30px;
  font-weight: bold;
  background: linear-gradient(90deg, #fff, #0ff);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  /* margin-bottom: 10px; */
}
.sub-title {
  font-size: 12px;
  color: fff;
}
.time-weather {
  display: flex;
  gap: 20px;
  align-items: center;
  /* justify-content: center; */
}
.time {
  font-size: 24px;
  font-weight: bold;
}
.date {
  color: #fff;
}
.weather {
  display: flex;
  align-items: center;
  gap: 5px;
}
.main-content {
  flex: 1;
  display: flex;
  /* padding: 10px; */
  gap: 10px;
}
.left-panel {
  width: 400px;
  display: flex;
  position: fixed;
  top: 0;
  left: 0;
  height: calc(100vh);
  background: linear-gradient(to right, rgba(1, 85, 121, 0.8) 0%, rgba(1, 85, 121, 0.8) 20%, rgba(151, 190, 192, 0));
  /* margin-top: 100px; */
  /* padding-top: 10px; */
  z-index: 1002;
  flex-direction: column;
  padding-bottom: 200px;
  gap: 10px;
}
.bottom-charts {
  height: 200px;
  width: 700px;
  position: fixed;
  bottom: 0;
  left: 0;
  z-index: 1000;
  /* background: linear-gradient(to right, rgba(1, 85, 121, 0.1) 0%, rgba(1, 85, 121, 0.1) 50%, rgba(151, 190, 192, 0) 100%); */
}
.right-panel {
  width: 300px;
  display: flex;
  position: fixed;
  top: 0;
  right: 0;
  height: calc(100vh - 100px);
  margin-top: 100px;
  z-index: 1000;
  flex-direction: column;
  gap: 10px;
}
.center-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.map-container {
  flex: 1;
  border-radius: 8px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.05);
  width: 100%;
  height: 100%;
  min-height: 500px;
}
.bottom-charts {
  /* height: 200px; */
  display: flex;
  gap: 10px;
  /* margin-bottom: 40px; */
}
.stat-group {
  display: flex;
  gap: 10px;
}
.stat-item {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.icon-area,
.icon-money {
  width: 40px;
  height: 40px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 50%;
}
.stat-info {
  flex: 1;
}
.mt-10 {
  margin-top: 10px;
}
.stat-label {
  font-size: 14px;
  color: #fff;
  margin-bottom: 5px;
}
.stat-value {
  font-size: 24px;
  font-weight: bold;
  color: #0ff;
}
.unit {
  font-size: 14px;
  margin-left: 4px;
  color: #fff;
}
.chart-card {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 15px;
  min-height: 300px;
}
.chart-title {
  font-size: 16px;
  margin-bottom: 15px;
  color: #fff;
}
.area-chart {
  height: calc(100% - 30px);
}
.data-card {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 15px;
  height: 80px;
}
.data-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.data-title {
  font-size: 16px;
}
.data-tabs {
  display: flex;
  align-items: center;
  gap: 10px;
}
.tab-value {
  font-size: 30px;
  font-family: 'DIN ', 'DIN', sans-serif;
  font-weight: bold;
  color: #fff;
  /* font-family: "DINPro-Bold"; */
}
.status-list {
  background: rgba(146, 146, 146, 0.5);
  border-radius: 2px;
  margin-right: 20px;
  margin-top: 10px;
  padding: 15px;
  height: 500px;
  overflow: hidden;
}
.status-title {
  font-size: 16px;
  /* margin-bottom: 15px; */
}
.status-items {
  display: flex;
  flex-direction: column;
  gap: 10px;
  height: calc(100% - 45px);
  animation: scrollUp 20s linear infinite;
}
.status-items:hover {
  animation-play-state: paused;
}
.status-items-container {
  height: 100%;
  overflow: hidden;
}
@keyframes scrollUp {
  0% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(-50%);
  }
}
/* 隐藏滚动条 */
.status-items::-webkit-scrollbar {
  display: none;
}
.status-items {
  -ms-overflow-style: none;
  scrollbar-width: none;
}
.status-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* padding: 10px; */
  background: rgba(255, 255, 255, 0.05);
  border-radius: 4px;
}
.area-name {
  font-size: 12px;
}
.status-actions {
  display: flex;
  gap: 10px;
}
.action-btn {
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
  background: rgba(0, 255, 255, 0.2);
}
.chart-group {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 10px;
}
.income-chart,
.trend-chart {
  height: calc(100% - 30px);
}
.info-window {
  padding: 10px;
  background: rgba(146, 146, 146, 0.5);
  border-radius: 8px;
  z-index: 10003;
  min-width: 200px;
}
.info-title {
  font-size: 16px;
  font-weight: bold;
  color: #fff;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid #eee;
}
.info-content {
  font-size: 12px;
  color: #fff;
}
.info-content p {
  margin: 8px 0;
  line-height: 1.4;
}
.info-window[data-status="waiting"] .info-title {
  color: #fff;
}
.info-window[data-status="rented"] .info-title {
  color: #fff;
}
.amap-info {
  z-index: 10003 !important;
  display: block !important;
}
.amap-info-content {
  background: rgba(146, 146, 146, 0.5);
  padding: 0 !important;
}
.amap-info-sharp {
  display: none !important;
}
.right-panel-top {
  display: flex;
  background: rgba(146, 146, 146, 0.5);
  margin-top: 50px;
  padding-top: 10px;
  padding-bottom: 30px;
  border-radius: 2px;
  margin-right: 20px;
  border-left: 4px solid #87F7C7;
  /* height: 100px; */
}
.right-panel-top1 {
  display: flex;
  background: rgba(146, 146, 146, 0.5);
  margin-top: 10px;
  padding-top: 10px;
  padding-bottom: 30px;
  border-radius: 2px;
  margin-right: 20px;
  border-left: 4px solid #FFB822;
  /* height: 100px; */
}
</style>
src/views/HomeView.vue
File was deleted
src/views/service.js
New file
@@ -0,0 +1,10 @@
import request from '@/utils/request'
// 获取房屋地图分布
export function getData(data) {
    return request({
        url: '/api/screen/statics-data',
        method: 'get',
        data
    })
}
vite.config.js
@@ -1,18 +1,21 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import legacy from '@vitejs/plugin-legacy'
import vue2 from '@vitejs/plugin-vue2'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue2(),
    legacy({
      targets: ['ie >= 11'],
      additionalLegacyPolyfills: ['regenerator-runtime/runtime']
    })
  ],
  plugins: [vue2()],
  publicPath: './',
  server: {
    proxy: {
      "/api": {
        target: "http://192.168.110.111:8081",
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    },
  },
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))