Переглянути джерело

生成了个首页,感觉还行

wukai 4 місяців тому
батько
коміт
493464190b
5 змінених файлів з 1317 додано та 3 видалено
  1. 1 1
      .env.development
  2. 824 0
      src/views/index.vue
  3. 490 0
      src/views/indexbak.vue
  4. 1 1
      src/views/login.vue
  5. 1 1
      src/views/register.vue

+ 1 - 1
.env.development

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = 出入境人员智能分析系统
+VITE_APP_TITLE = 出入境智能分析系统
 
 # 开发环境配置
 VITE_APP_ENV = 'development'

+ 824 - 0
src/views/index.vue

@@ -1,2 +1,826 @@
 <template>
+  <div class="app-container">
+    <!-- 统计数据卡片 -->
+    <el-row :gutter="20" class="mb20">
+      <el-col :span="4">
+        <el-card class="stat-card total-people">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.totalPeople }}</div>
+            <div class="stat-label">总人数</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="4">
+        <el-card class="stat-card total-entries">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.totalEntries }}</div>
+            <div class="stat-label">总次数</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="4">
+        <el-card class="stat-card avg-frequency">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.avgFrequency }}</div>
+            <div class="stat-label">平均频次</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="4">
+        <el-card class="stat-card max-frequency">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.maxFrequency }}</div>
+            <div class="stat-label">最高频次</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="4">
+        <el-card class="stat-card night-entries">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.nightPeople }}</div>
+            <div class="stat-label">夜间出入境人数</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="4">
+        <el-card class="stat-card holiday-entries">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.holidayPeople }}</div>
+            <div class="stat-label">节假日出入境人数</div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 图表区域 -->
+    <el-row :gutter="20" class="mb20">
+      <el-col :span="12">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="chart-header">
+              <span>出入境频次分布</span>
+            </div>
+          </template>
+          <div class="chart-container" ref="pieChartContainer" style="height: 300px;"></div>
+        </el-card>
+      </el-col>
+      <el-col :span="12">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="chart-header">
+              <span>节假日出入境</span>
+            </div>
+          </template>
+          <div class="holiday-container" style="height: 300px; overflow-y: auto; padding: 20px;">
+            <div v-loading="holidayLoading" class="holiday-list">
+              <div v-for="(item, index) in holidayList" :key="index" class="holiday-item">
+                <div class="holiday-content">
+                  <span class="holiday-name">{{ item.holidayName }}</span>
+                  <span class="holiday-dates">({{ item.startDate }}至{{ item.endDate }})</span>
+                  <span class="holiday-count">{{ item.inOutCount }}次</span>
+                </div>
+              </div>
+              <div v-if="holidayList.length === 0 && holidayLoading" class="no-data">
+                <span>加载中...</span>
+              </div>
+              <div v-if="holidayList.length === 0 && !holidayLoading" class="no-data">
+                <span>暂无数据</span>
+              </div>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <el-row :gutter="20" class="mb20">
+      <el-col :span="24">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="chart-header">
+              <span>夜间出入境趋势</span>
+            </div>
+          </template>
+          <div class="chart-container" ref="nightChartContainer" style="height: 300px;"></div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 快捷入口 -->
+    <el-row :gutter="20">
+      <el-col :span="24">
+        <el-card class="quick-access-card">
+          <template #header>
+            <div class="card-header">
+              <span>快捷入口</span>
+            </div>
+          </template>
+          <div class="quick-access-grid">
+            <div class="quick-item" @click="goToPage('/anal/high')">
+              <div class="quick-icon bg-blue">
+                <el-icon><TrendCharts /></el-icon>
+              </div>
+              <div class="quick-text">高频出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/anal/night')">
+              <div class="quick-icon bg-purple">
+                <el-icon><Moon /></el-icon>
+              </div>
+              <div class="quick-text">夜间出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/anal/holiday')">
+              <div class="quick-icon bg-green">
+                <el-icon><Calendar /></el-icon>
+              </div>
+              <div class="quick-text">节假日出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/anal/rapid')">
+              <div class="quick-icon bg-orange">
+                <el-icon><Lightning /></el-icon>
+              </div>
+              <div class="quick-text">短期往返分析</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/anal/low')">
+              <div class="quick-icon bg-red">
+                <el-icon><Document /></el-icon>
+              </div>
+              <div class="quick-text">低频出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/anal/overstay')">
+              <div class="quick-icon bg-cyan">
+                <el-icon><Timer /></el-icon>
+              </div>
+              <div class="quick-text">境外滞留分析</div>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
 </template>
+
+<script setup name="Index">
+import * as echarts from 'echarts'
+import { onMounted, onUnmounted, ref, reactive, toRefs, nextTick } from 'vue'
+import { House, TrendCharts, Moon, Calendar, Lightning, Document, Timer } from '@element-plus/icons-vue'
+import { useRouter } from 'vue-router'
+import { getInOutStats, listHighFrequencyInOut, getNightInOutStats, getHolidayInOutStats } from "@/api/biz/anal";
+
+const router = useRouter()
+
+const holidayList = ref([]);
+const holidayLoading = ref(false);
+
+const pieChartContainer = ref(null);
+const nightChartContainer = ref(null);
+
+const statistics = ref({
+  totalPeople: 0,
+  totalEntries: 0,
+  avgFrequency: 0,
+  maxFrequency: 0,
+  nightPeople: 0,
+  holidayPeople: 0
+});
+
+// 直接使用当年查询,不再需要查询表单
+const data = reactive({
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    year: new Date().getFullYear().toString()  // 直接使用当前年份
+  }
+});
+
+const { queryParams } = toRefs(data);
+
+/** 查询数据 */
+function getList() {
+  // 准备查询参数 - 直接使用当前年份
+  const params = {
+    year: queryParams.value.year
+  };
+
+  // 设置加载状态
+  holidayLoading.value = true;
+
+  // 并行调用所有需要的API
+  Promise.all([
+    getInOutStats(params),           // 基础统计
+    getNightInOutStats(params),      // 夜间统计
+    getHolidayInOutStats(params),    // 节假日统计
+    listHighFrequencyInOut(params)   // 高频数据用于频次分布
+  ]).then(responses => {
+    console.log('API响应数据:', responses); // 调试信息
+
+    // 处理基础统计信息
+    const statsResponse = responses[0];
+    if (statsResponse.code === 200 && statsResponse.data) {
+      const stats = statsResponse.data;
+      statistics.value.totalPeople = stats.totalPeople || 0;
+      statistics.value.totalEntries = stats.totalCount || 0;
+      statistics.value.avgFrequency = Number(stats.avgFrequency).toFixed(2) || 0;
+      statistics.value.maxFrequency = stats.maxFrequency || 0;
+    }
+
+    // 处理夜间统计信息
+    const nightResponse = responses[1];
+    if (nightResponse.code === 200 && nightResponse.data) {
+      const nightStats = nightResponse.data;
+      statistics.value.nightPeople = nightStats.totalPeople || 0;
+    }
+
+    // 处理节假日统计信息
+    const holidayResponse = responses[2];
+    console.log('节假日统计响应:', holidayResponse); // 调试信息
+    if (holidayResponse.code === 200) {
+      // 节假日统计数据结构为数组,包含节假日名称、出入境次数等信息
+      const holidayData = Array.isArray(holidayResponse.data) ? holidayResponse.data : [];
+      console.log('节假日统计数据:', holidayData); // 调试信息
+
+      // 计算总人数
+      const totalHolidayCount = holidayData.reduce((sum, item) => sum + (item.inOutCount || 0), 0);
+      statistics.value.holidayPeople = totalHolidayCount;
+
+      // 处理节假日列表数据
+      holidayList.value = holidayData.map(item => ({
+        holidayName: item.holidayName,
+        inOutCount: item.inOutCount,
+        startDate: item.startDate,
+        endDate: item.endDate
+      }));
+    } else {
+      console.error('节假日数据获取失败:', holidayResponse);
+      holidayList.value = [];
+      statistics.value.holidayPeople = 0;
+    }
+
+    // 更新图表
+    nextTick(() => {
+      renderPieChart(params);        // 频次分布饼图
+      renderNightChart(params);      // 夜间趋势图
+    });
+  }).catch(error => {
+    console.error('获取统计数据失败:', error);
+    holidayList.value = [];
+    statistics.value.holidayPeople = 0;
+  }).finally(() => {
+    holidayLoading.value = false;
+  });
+}
+
+/** 渲染出入境频次分布饼图 */
+function renderPieChart(params) {
+  if (!pieChartContainer.value) return;
+
+  const myChart = echarts.init(pieChartContainer.value);
+
+  // 调用后端接口获取频次分布数据
+  getInOutStats(params).then(response => {
+    let distributionData = [];
+
+    if (response.code === 200 && response.data) {
+      const stats = response.data;
+
+      // 检查是否有频次分布数据
+      if (stats.frequencyDistribution && typeof stats.frequencyDistribution === 'object') {
+        const dist = stats.frequencyDistribution;
+        distributionData = [];
+
+        // 将对象格式转换为饼图需要的数组格式,并按区间排序
+        const rangeOrder = ['1-5', '5-10', '10-20', '20-30', '30+'];
+
+        // 先处理预定义的区间
+        for (const range of rangeOrder) {
+          if (dist.hasOwnProperty(range)) {
+            // 根据区间范围选择颜色
+            let color;
+            if (range.startsWith('1-5')) color = '#5470c6';
+            else if (range.startsWith('5-10')) color = '#91cc75';
+            else if (range.startsWith('10-20')) color = '#fac858';
+            else if (range.startsWith('20-30')) color = '#ee6666';
+            else if (range.startsWith('30')) color = '#73c0de';
+            else color = '#9da4b0';
+
+            distributionData.push({
+              value: dist[range],
+              name: range,
+              itemStyle: { color: color }
+            });
+          }
+        }
+
+        // 处理不在预定义区间中的其他区间
+        for (const [range, count] of Object.entries(dist)) {
+          if (!rangeOrder.includes(range)) {
+            let color;
+            if (range.startsWith('1-5')) color = '#5470c6';
+            else if (range.startsWith('5-10')) color = '#91cc75';
+            else if (range.startsWith('10-20')) color = '#fac858';
+            else if (range.startsWith('20-30')) color = '#ee6666';
+            else if (range.startsWith('30')) color = '#73c0de';
+            else color = '#9da4b0';
+
+            distributionData.push({
+              value: count,
+              name: range,
+              itemStyle: { color: color }
+            });
+          }
+        }
+      }
+    }
+
+    const option = {
+      tooltip: {
+        trigger: 'item',
+        formatter: '{a} <br/>{b}: {c}人 ({d}%)'
+      },
+      legend: {
+        orient: 'vertical',
+        left: 'right'
+      },
+      series: [{
+        name: '人数',
+        type: 'pie',
+        radius: [20, 120], // 设置内外半径,形成南丁格尔图效果
+        center: ['50%', '50%'],
+        roseType: 'area', // 启用南丁格尔图模式
+        itemStyle: {
+          borderRadius: 8
+        },
+        label: {
+          show: true,
+          formatter: '{b}: {c}',
+          fontSize: 10,
+          position: 'outside'
+        },
+        data: distributionData,
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowOffsetX: 0,
+            shadowColor: 'rgba(0, 0, 0, 0.5)'
+          }
+        }
+      }]
+    };
+
+    myChart.setOption(option);
+  }).catch(() => {
+    const option = {
+      tooltip: {
+        trigger: 'item'
+      },
+      legend: {
+        orient: 'vertical',
+        left: 'right'
+      },
+      series: [{
+        name: '人数',
+        type: 'pie',
+        radius: [20, 120],
+        center: ['50%', '50%'],
+        roseType: 'area',
+        itemStyle: {
+          borderRadius: 8
+        },
+        label: {
+          show: true,
+          formatter: '{b}: {c}',
+          fontSize: 10,
+          position: 'outside'
+        },
+        data: [],
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowOffsetX: 0,
+            shadowColor: 'rgba(0, 0, 0, 0.5)'
+          }
+        }
+      }]
+    };
+
+    myChart.setOption(option);
+  });
+}
+
+/** 渲染夜间出入境趋势图 */
+function renderNightChart(params) {
+  if (!nightChartContainer.value) return;
+
+  const myChart = echarts.init(nightChartContainer.value);
+
+  getNightInOutStats(params).then(response => {
+    let xAxisData = [];
+    let seriesData = [];
+
+    if (response.code === 200 && response.data) {
+      const stats = response.data;
+
+      // 使用趋势数据
+      if (stats.trendData && Array.isArray(stats.trendData)) {
+        // 按年查询,显示每月趋势
+        xAxisData = stats.trendData.map(item => {
+          if (item.period) {
+            const parts = item.period.split('-');
+            if (parts.length === 2) {
+              return parts[1] + '月';
+            }
+          }
+          return '未知';
+        });
+
+        // 获取人数或次数数据
+        seriesData = stats.trendData.map(item => item.inOutCount !== undefined ? item.inOutCount : 0);
+      }
+    }
+
+    const option = {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        },
+        formatter: (params) => {
+          const param = params[0];
+          if (param.name === '暂无数据') {
+            return '暂无数据';
+          }
+          const date = xAxisData[param.dataIndex];
+          const value = param.value;
+          return `${date}<br/>夜间出入境人数:${value}`;
+        }
+      },
+      grid: {
+        show: false
+      },
+      xAxis: {
+        type: 'category',
+        data: xAxisData,
+        axisLabel: {
+          rotate: 45,
+          fontSize: 12
+        },
+        boundaryGap: false
+      },
+      yAxis: {
+        type: 'value',
+        name: '人数',
+        show: true
+      },
+      series: [{
+        data: seriesData,
+        type: 'line',
+        smooth: true,
+        symbol: 'emptyCircle',
+        symbolSize: 6,
+        lineStyle: {
+          color: '#73c0de',
+          width: 2
+        },
+        itemStyle: {
+          color: '#3ba272'
+        },
+        areaStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: 'rgba(115, 192, 222, 0.3)' },
+            { offset: 1, color: 'rgba(115, 192, 222, 0.05)' }
+          ])
+        }
+      }]
+    };
+
+    myChart.setOption(option);
+  }).catch(() => {
+    const option = {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        }
+      },
+      grid: {
+        show: false
+      },
+      xAxis: {
+        type: 'category',
+        data: ['暂无数据'],
+        axisLabel: {
+          rotate: 45,
+          fontSize: 12
+        },
+        boundaryGap: false
+      },
+      yAxis: {
+        type: 'value',
+        name: '人数',
+        show: true
+      },
+      series: [{
+        data: [0],
+        type: 'line',
+        smooth: true,
+        symbol: 'emptyCircle',
+        symbolSize: 6,
+        lineStyle: {
+          color: '#73c0de',
+          width: 2
+        },
+        itemStyle: {
+          color: '#3ba272'
+        }
+      }]
+    };
+
+    myChart.setOption(option);
+  });
+}
+
+/** 跳转到指定页面 */
+function goToPage(path) {
+  router.push(path)
+}
+
+// 页面加载时获取数据 - 直接查询当年数据
+onMounted(() => {
+  getList();
+});
+
+// 组件卸载时销毁图表
+onUnmounted(() => {
+  if (pieChartContainer.value) {
+    const pieChart = echarts.getInstanceByDom(pieChartContainer.value);
+    if (pieChart) pieChart.dispose();
+  }
+
+  if (nightChartContainer.value) {
+    const nightChart = echarts.getInstanceByDom(nightChartContainer.value);
+    if (nightChart) nightChart.dispose();
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  padding: 20px;
+  background-color: #f5f7f9;
+}
+
+.stat-card {
+  text-align: center;
+  border-radius: 12px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s ease;
+  height: 100px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.stat-card:hover {
+  transform: translateY(-3px);
+  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
+}
+
+.stat-card.total-people {
+  background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
+  color: #1890ff;
+}
+
+.stat-card.total-entries {
+  background: linear-gradient(135deg, #f6ffed 0%, #d9f7be 100%);
+  color: #52c41a;
+}
+
+.stat-card.avg-frequency {
+  background: linear-gradient(135deg, #fffbe6 0%, #fff5a0 100%);
+  color: #faad14;
+}
+
+.stat-card.max-frequency {
+  background: linear-gradient(135deg, #fff2f0 0%, #ffccc7 100%);
+  color: #f5222d;
+}
+
+.stat-card.night-entries {
+  background: linear-gradient(135deg, #f0f9ff 0%, #c0e8ff 100%);
+  color: #409eff;
+}
+
+.stat-card.holiday-entries {
+  background: linear-gradient(135deg, #fff0f5 0%, #ffd6e7 100%);
+  color: #f759ab;
+}
+
+.stat-item {
+  width: 100%;
+  padding: 10px;
+}
+
+.stat-number {
+  font-size: 24px;
+  font-weight: bold;
+  margin-bottom: 5px;
+}
+
+.stat-label {
+  font-size: 13px;
+  color: #606266;
+  font-weight: 500;
+}
+
+.chart-card {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  margin-bottom: 20px;
+}
+
+.chart-header {
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.chart-container {
+  width: 100%;
+  height: 100%;
+}
+
+.table-container {
+  width: 100%;
+  padding: 0 20px 20px 20px;
+}
+
+.holiday-container {
+  width: 100%;
+}
+
+.holiday-list {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.holiday-item {
+  padding: 12px 16px;
+  border: 1px solid #c0e8ff;
+  border-radius: 6px;
+  background-color: #f0f9ff;
+  transition: all 0.3s ease;
+  box-shadow: 0 1px 4px rgba(192, 232, 255, 0.3);
+}
+
+.holiday-item:hover {
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  border-color: #c0c4cc;
+  transform: translateY(-2px);
+}
+
+.holiday-content {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+
+.holiday-name {
+  font-weight: 600;
+  font-size: 14px;
+  color: #1890ff;
+  margin-right: 6px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.holiday-dates {
+  font-size: 12px;
+  color: #52c41a;
+  margin-right: 12px;
+  white-space: nowrap;
+}
+
+.holiday-count {
+  font-weight: 600;
+  font-size: 14px;
+  color: #f5222d;
+  margin-left: auto;
+  white-space: nowrap;
+}
+
+.no-data {
+  text-align: center;
+  padding: 40px 0;
+  color: #909399;
+  font-style: italic;
+}
+
+.data-card {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.card-header {
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.quick-access-card {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.quick-access-grid {
+  display: grid;
+  grid-template-columns: repeat(6, 1fr);
+  gap: 20px;
+}
+
+.quick-item {
+  text-align: center;
+  cursor: pointer;
+  padding: 20px 10px;
+  border-radius: 8px;
+  transition: all 0.3s ease;
+  background-color: #fafafa;
+}
+
+.quick-item:hover {
+  transform: translateY(-3px);
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  background-color: #fff;
+}
+
+.quick-icon {
+  width: 60px;
+  height: 60px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 0 auto 10px;
+  border-radius: 10px;
+  font-size: 24px;
+  color: white;
+}
+
+.bg-blue {
+  background: linear-gradient(135deg, #409eff 0%, #4a9eff 100%);
+}
+
+.bg-purple {
+  background: linear-gradient(135deg, #7265e3 0%, #7a6de3 100%);
+}
+
+.bg-green {
+  background: linear-gradient(135deg, #20c997 0%, #26d19c 100%);
+}
+
+.bg-orange {
+  background: linear-gradient(135deg, #f56c6c 0%, #f67878 100%);
+}
+
+.bg-red {
+  background: linear-gradient(135deg, #e6a23c 0%, #eca742 100%);
+}
+
+.bg-cyan {
+  background: linear-gradient(135deg, #17b3a3 0%, #19c0b2 100%);
+}
+
+.quick-text {
+  font-size: 14px;
+  color: #303133;
+  font-weight: 500;
+}
+
+.mb20 {
+  margin-bottom: 20px;
+}
+
+@media (max-width: 1200px) {
+  .quick-access-grid {
+    grid-template-columns: repeat(3, 1fr);
+  }
+}
+
+@media (max-width: 768px) {
+  .quick-access-grid {
+    grid-template-columns: repeat(2, 1fr);
+  }
+
+  .el-col-4 {
+    width: 50%;
+    margin-bottom: 15px;
+  }
+
+  .el-col-12 {
+    width: 100%;
+  }
+
+  .el-row {
+    margin-bottom: 15px;
+  }
+}
+</style>

+ 490 - 0
src/views/indexbak.vue

@@ -0,0 +1,490 @@
+<template>
+  <div class="app-container">
+    <div class="welcome-section">
+      <el-card class="welcome-card">
+        <div class="welcome-content">
+          <div class="welcome-icon">
+            <el-icon><House /></el-icon>
+          </div>
+          <h2 class="welcome-title">欢迎使用出入境业务分析系统</h2>
+          <p class="welcome-desc">实时监控出入境数据,智能分析业务趋势</p>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- 统计数据卡片 -->
+    <el-row :gutter="20" class="mb20">
+      <el-col :span="6">
+        <el-card class="stat-card total-people">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.totalEntries }}</div>
+            <div class="stat-label">今日出入境总人数</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card class="stat-card total-entries">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.nightEntries }}</div>
+            <div class="stat-label">夜间出入境人数</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card class="stat-card avg-frequency">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.holidayEntries }}</div>
+            <div class="stat-label">节假日出入境人数</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card class="stat-card max-frequency">
+          <div class="stat-item">
+            <div class="stat-number">{{ statistics.rapidTravellers }}</div>
+            <div class="stat-label">短期往返人员数</div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 业务概览图表 -->
+    <el-row :gutter="20" class="mb20">
+      <el-col :span="12">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="chart-header">
+              <span>出入境趋势统计</span>
+            </div>
+          </template>
+          <div class="chart-container" ref="trendChartContainer" style="height: 300px;"></div>
+        </el-card>
+      </el-col>
+      <el-col :span="12">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="chart-header">
+              <span>业务类型分布</span>
+            </div>
+          </template>
+          <div class="chart-container" ref="pieChartContainer" style="height: 300px;"></div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 快捷入口 -->
+    <el-row :gutter="20">
+      <el-col :span="24">
+        <el-card class="quick-access-card">
+          <template #header>
+            <div class="card-header">
+              <span>快捷入口</span>
+            </div>
+          </template>
+          <div class="quick-access-grid">
+            <div class="quick-item" @click="goToPage('/biz/anal/high')">
+              <div class="quick-icon bg-blue">
+                <el-icon><TrendCharts /></el-icon>
+              </div>
+              <div class="quick-text">高频出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/biz/anal/night')">
+              <div class="quick-icon bg-purple">
+                <el-icon><Moon /></el-icon>
+              </div>
+              <div class="quick-text">夜间出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/biz/anal/holiday')">
+              <div class="quick-icon bg-green">
+                <el-icon><Calendar /></el-icon>
+              </div>
+              <div class="quick-text">节假日出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/biz/anal/rapid')">
+              <div class="quick-icon bg-orange">
+                <el-icon><Lightning /></el-icon>
+              </div>
+              <div class="quick-text">短期往返分析</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/biz/anal/low')">
+              <div class="quick-icon bg-red">
+                <el-icon><Document /></el-icon>
+              </div>
+              <div class="quick-text">低频出入境</div>
+            </div>
+            <div class="quick-item" @click="goToPage('/biz/anal/overstay')">
+              <div class="quick-icon bg-cyan">
+                <el-icon><Timer /></el-icon>
+              </div>
+              <div class="quick-text">境外滞留分析</div>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup name="Index">
+import * as echarts from 'echarts'
+import { onMounted, onUnmounted, ref, reactive, nextTick } from 'vue'
+import { House, TrendCharts, Moon, Calendar, Lightning, Document, Timer } from '@element-plus/icons-vue'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+
+// 统计数据
+const statistics = ref({
+  totalEntries: 0,
+  nightEntries: 0,
+  holidayEntries: 0,
+  rapidTravellers: 0
+})
+
+// 图表容器引用
+const trendChartContainer = ref(null)
+const pieChartContainer = ref(null)
+
+// 模拟数据
+const trendData = [
+  { date: '周一', count: 1200 },
+  { date: '周二', count: 1500 },
+  { date: '周三', count: 1800 },
+  { date: '周四', count: 1600 },
+  { date: '周五', count: 2000 },
+  { date: '周六', count: 2200 },
+  { date: '周日', count: 1900 }
+]
+
+const pieData = [
+  { name: '高频出入境', value: 35 },
+  { name: '夜间出入境', value: 20 },
+  { name: '节假日出入境', value: 15 },
+  { name: '短期往返', value: 10 },
+  { name: '低频出入境', value: 12 },
+  { name: '境外滞留', value: 8 }
+]
+
+// 渲染趋势图
+function renderTrendChart() {
+  if (!trendChartContainer.value) return
+
+  const myChart = echarts.init(trendChartContainer.value)
+
+  const option = {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow'
+      }
+    },
+    xAxis: {
+      type: 'category',
+      data: trendData.map(item => item.date),
+      axisLabel: {
+        fontSize: 12
+      }
+    },
+    yAxis: {
+      type: 'value',
+      name: '人数'
+    },
+    series: [{
+      data: trendData.map(item => item.count),
+      type: 'line',
+      smooth: true,
+      itemStyle: {
+        color: '#409eff'
+      },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: 'rgba(64, 158, 255, 0.4)' },
+          { offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
+        ])
+      }
+    }]
+  }
+
+  myChart.setOption(option)
+}
+
+// 渲染饼图
+function renderPieChart() {
+  if (!pieChartContainer.value) return
+
+  const myChart = echarts.init(pieChartContainer.value)
+
+  const option = {
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      orient: 'vertical',
+      left: 'right'
+    },
+    series: [{
+      name: '业务类型',
+      type: 'pie',
+      radius: '50%',
+      data: pieData,
+      emphasis: {
+        itemStyle: {
+          shadowBlur: 10,
+          shadowOffsetX: 0,
+          shadowColor: 'rgba(0, 0, 0, 0.5)'
+        }
+      }
+    }]
+  }
+
+  myChart.setOption(option)
+}
+
+// 跳转到指定页面
+function goToPage(path) {
+  router.push(path)
+}
+
+// 初始化数据
+function initDashboard() {
+  // 模拟统计数据
+  statistics.value = {
+    totalEntries: 12543,
+    nightEntries: 892,
+    holidayEntries: 2103,
+    rapidTravellers: 342
+  }
+
+  // 渲染图表
+  nextTick(() => {
+    renderTrendChart()
+    renderPieChart()
+  })
+}
+
+// 页面加载时初始化
+onMounted(() => {
+  initDashboard()
+})
+
+// 组件卸载时销毁图表
+onUnmounted(() => {
+  if (trendChartContainer.value) {
+    const trendChart = echarts.getInstanceByDom(trendChartContainer.value)
+    if (trendChart) trendChart.dispose()
+  }
+  
+  if (pieChartContainer.value) {
+    const pieChart = echarts.getInstanceByDom(pieChartContainer.value)
+    if (pieChart) pieChart.dispose()
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  padding: 20px;
+  background-color: #f5f7f9;
+}
+
+.welcome-section {
+  margin-bottom: 20px;
+
+  .welcome-card {
+    background: linear-gradient(135deg, #7265e3 0%, #3f87e3 50%, #20c997 100%);
+    color: white;
+    border: none;
+    border-radius: 12px;
+    overflow: hidden;
+
+    .welcome-content {
+      text-align: center;
+      padding: 30px;
+
+      .welcome-icon {
+        font-size: 48px;
+        margin-bottom: 15px;
+      }
+
+      .welcome-title {
+        font-size: 24px;
+        margin: 10px 0;
+        font-weight: 500;
+      }
+
+      .welcome-desc {
+        font-size: 16px;
+        opacity: 0.9;
+      }
+    }
+  }
+}
+
+.stat-card {
+  text-align: center;
+  border-radius: 12px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s ease;
+  height: 100px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.stat-card:hover {
+  transform: translateY(-3px);
+  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
+}
+
+.stat-card.total-people {
+  background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
+  color: #1890ff;
+}
+
+.stat-card.total-entries {
+  background: linear-gradient(135deg, #f6ffed 0%, #d9f7be 100%);
+  color: #52c41a;
+}
+
+.stat-card.avg-frequency {
+  background: linear-gradient(135deg, #fffbe6 0%, #fff5a0 100%);
+  color: #faad14;
+}
+
+.stat-card.max-frequency {
+  background: linear-gradient(135deg, #fff2f0 0%, #ffccc7 100%);
+  color: #f5222d;
+}
+
+.stat-item {
+  width: 100%;
+  padding: 10px;
+}
+
+.stat-number {
+  font-size: 24px;
+  font-weight: bold;
+  margin-bottom: 5px;
+}
+
+.stat-label {
+  font-size: 13px;
+  color: #606266;
+  font-weight: 500;
+}
+
+.chart-card {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.chart-header {
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.chart-container {
+  width: 100%;
+  height: 100%;
+}
+
+.quick-access-card {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.card-header {
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.quick-access-grid {
+  display: grid;
+  grid-template-columns: repeat(6, 1fr);
+  gap: 20px;
+}
+
+.quick-item {
+  text-align: center;
+  cursor: pointer;
+  padding: 20px 10px;
+  border-radius: 8px;
+  transition: all 0.3s ease;
+  background-color: #fafafa;
+}
+
+.quick-item:hover {
+  transform: translateY(-3px);
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  background-color: #fff;
+}
+
+.quick-icon {
+  width: 60px;
+  height: 60px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 0 auto 10px;
+  border-radius: 10px;
+  font-size: 24px;
+  color: white;
+}
+
+.bg-blue {
+  background: linear-gradient(135deg, #409eff 0%, #4a9eff 100%);
+}
+
+.bg-purple {
+  background: linear-gradient(135deg, #7265e3 0%, #7a6de3 100%);
+}
+
+.bg-green {
+  background: linear-gradient(135deg, #20c997 0%, #26d19c 100%);
+}
+
+.bg-orange {
+  background: linear-gradient(135deg, #f56c6c 0%, #f67878 100%);
+}
+
+.bg-red {
+  background: linear-gradient(135deg, #e6a23c 0%, #eca742 100%);
+}
+
+.bg-cyan {
+  background: linear-gradient(135deg, #17b3a3 0%, #19c0b2 100%);
+}
+
+.quick-text {
+  font-size: 14px;
+  color: #303133;
+  font-weight: 500;
+}
+
+.mb20 {
+  margin-bottom: 20px;
+}
+
+@media (max-width: 1200px) {
+  .quick-access-grid {
+    grid-template-columns: repeat(3, 1fr);
+  }
+}
+
+@media (max-width: 768px) {
+  .quick-access-grid {
+    grid-template-columns: repeat(2, 1fr);
+  }
+  
+  .el-col-6 {
+    width: 100%;
+    margin-bottom: 15px;
+  }
+  
+  .el-row {
+    margin-bottom: 15px;
+  }
+}
+</style>

+ 1 - 1
src/views/login.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="login">
     <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
-      <h3 class="title">出入境人员智能分析系统</h3>
+      <h3 class="title">出入境智能分析系统</h3>
       <el-form-item prop="username">
         <el-input
           v-model="loginForm.username"

+ 1 - 1
src/views/register.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="register">
     <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
-      <h3 class="title">出入境人员智能分析系统</h3>
+      <h3 class="title">出入境智能分析系统</h3>
       <el-form-item prop="username">
         <el-input
           v-model="registerForm.username"