|
@@ -0,0 +1,652 @@
|
|
|
+<template>
|
|
|
+ <div class="statistics-container">
|
|
|
+ <!-- 页面标题 -->
|
|
|
+ <h1 class="page-title">辽宁凤凰山景区票务统计</h1>
|
|
|
+
|
|
|
+ <!-- 日期选择器 -->
|
|
|
+ <el-card class="date-selector-card">
|
|
|
+ <div class="date-selector-wrapper">
|
|
|
+ <span class="date-label">选择日期:</span>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="selectedDate"
|
|
|
+ type="date"
|
|
|
+ placeholder="选择日期"
|
|
|
+ :shortcuts="dateShortcuts"
|
|
|
+ @change="handleDateChange"
|
|
|
+ class="date-picker"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 统计数据卡片网格 -->
|
|
|
+ <div class="statistics-grid">
|
|
|
+ <!-- 模块1:售票数据 -->
|
|
|
+ <el-card class="statistics-card sales-card" :body-style="{ padding: '0' }">
|
|
|
+ <template #header>
|
|
|
+ <div class="card-header">
|
|
|
+ <span class="card-title">当日售票数据</span>
|
|
|
+ <el-tag type="success" size="small">{{ dayjs(selectedDate).format('YYYY年MM月DD日') }}</el-tag>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="card-content">
|
|
|
+ <!-- 线上售票数据 -->
|
|
|
+ <div class="data-section">
|
|
|
+ <h3 class="section-title"><i class="el-icon-mobile-phone"></i> 线上售票</h3>
|
|
|
+ <div class="data-list">
|
|
|
+ <div class="data-item" v-for="(item, index) in onlineData" :key="index">
|
|
|
+ <span class="label">{{ item.label }}</span>
|
|
|
+ <span class="value highlight-value">{{ item.value }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="total-item">
|
|
|
+ <span class="label">线上总计</span>
|
|
|
+ <span class="value total-value">{{ getTotalOnline() }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 线下售票数据 -->
|
|
|
+ <div class="data-section">
|
|
|
+ <h3 class="section-title"><i class="el-icon-office-building"></i> 线下售票</h3>
|
|
|
+ <div class="data-list">
|
|
|
+ <div class="data-item" v-for="(item, index) in offlineData" :key="index">
|
|
|
+ <span class="label">{{ item.label }}</span>
|
|
|
+ <span class="value highlight-value">{{ item.value }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="total-item">
|
|
|
+ <span class="label">线下总计</span>
|
|
|
+ <span class="value total-value">{{ getTotalOffline() }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 模块2:检票数据 -->
|
|
|
+ <el-card class="statistics-card check-card" :body-style="{ padding: '0' }">
|
|
|
+ <template #header>
|
|
|
+ <div class="card-header">
|
|
|
+ <span class="card-title">当日检票数据</span>
|
|
|
+ <el-tag type="warning" size="small">{{ dayjs(selectedDate).format('YYYY年MM月DD日') }}</el-tag>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="card-content">
|
|
|
+ <div class="check-data-container">
|
|
|
+ <!-- 检票数据图表 -->
|
|
|
+ <div class="check-chart">
|
|
|
+ <div class="chart-placeholder">
|
|
|
+ <!-- 这里可以放置一个饼图或柱状图 -->
|
|
|
+ <div class="chart-circle" v-for="(item, index) in checkData" :key="index"
|
|
|
+ :style="{
|
|
|
+ width: `${getPercentage(item.value, getTotalCheck())}%`,
|
|
|
+ backgroundColor: getColorByIndex(index)
|
|
|
+ }">
|
|
|
+ {{ item.label }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 检票数据列表 -->
|
|
|
+ <div class="data-list">
|
|
|
+ <div class="data-item" v-for="(item, index) in checkData" :key="index">
|
|
|
+ <div class="label-with-color">
|
|
|
+ <span class="color-dot" :style="{ backgroundColor: getColorByIndex(index) }"></span>
|
|
|
+ <span class="label">{{ item.label }}</span>
|
|
|
+ </div>
|
|
|
+ <span class="value highlight-value">{{ item.value }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="total-item">
|
|
|
+ <span class="label">检票总计</span>
|
|
|
+ <span class="value total-value">{{ getTotalCheck() }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 模块3:收入数据 -->
|
|
|
+ <el-card class="statistics-card income-card" :body-style="{ padding: '0' }">
|
|
|
+ <template #header>
|
|
|
+ <div class="card-header">
|
|
|
+ <span class="card-title">当日收入</span>
|
|
|
+ <el-tag type="primary" size="small">{{ dayjs(selectedDate).format('YYYY年MM月DD日') }}</el-tag>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="card-content">
|
|
|
+ <!-- 总收入展示 -->
|
|
|
+ <div class="total-income">
|
|
|
+ <div class="income-label">总收入</div>
|
|
|
+ <div class="income-amount">
|
|
|
+ <span class="income-icon">¥</span>
|
|
|
+ {{ formatCurrency(incomeData.total) }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 收入明细 -->
|
|
|
+ <div class="income-details">
|
|
|
+ <div class="data-item" v-for="(item, index) in incomeData.details" :key="index">
|
|
|
+ <span class="label">{{ item.label }}</span>
|
|
|
+ <span class="value income-value">¥{{ formatCurrency(item.value) }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 收入占比条 -->
|
|
|
+ <div class="income-ratio-bar">
|
|
|
+ <div class="ratio-segment online-segment"
|
|
|
+ :style="{ width: `${(incomeData.details[0].value / incomeData.total) * 100}%` }">
|
|
|
+ {{ Math.round((incomeData.details[0].value / incomeData.total) * 100) }}%
|
|
|
+ </div>
|
|
|
+ <div class="ratio-segment offline-segment"
|
|
|
+ :style="{ width: `${(incomeData.details[1].value / incomeData.total) * 100}%` }">
|
|
|
+ {{ Math.round((incomeData.details[1].value / incomeData.total) * 100) }}%
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ratio-legend">
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="color-dot online-dot"></span>
|
|
|
+ <span>线上收入</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="color-dot offline-dot"></span>
|
|
|
+ <span>线下收入</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted, computed } from 'vue'
|
|
|
+import { getStatisticsData } from '@/api/statistics'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+
|
|
|
+// 日期选择
|
|
|
+const selectedDate = ref(new Date())
|
|
|
+const dateShortcuts = [
|
|
|
+ {
|
|
|
+ text: '今天',
|
|
|
+ value: new Date(),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '昨天',
|
|
|
+ value: () => {
|
|
|
+ const date = new Date()
|
|
|
+ date.setTime(date.getTime() - 3600 * 1000 * 24)
|
|
|
+ return date
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '上周同日',
|
|
|
+ value: () => {
|
|
|
+ const date = new Date()
|
|
|
+ date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
|
|
|
+ return date
|
|
|
+ },
|
|
|
+ },
|
|
|
+]
|
|
|
+
|
|
|
+// 模拟数据
|
|
|
+const onlineData = ref([
|
|
|
+ { label: '小程序', value: 0 },
|
|
|
+ { label: '抖音', value: 0 },
|
|
|
+ { label: '美团', value: 0 },
|
|
|
+ { label: '携程', value: 0 }
|
|
|
+])
|
|
|
+
|
|
|
+const offlineData = ref([
|
|
|
+ { label: '窗口1', value: 0 },
|
|
|
+ { label: '窗口2', value: 0 }
|
|
|
+])
|
|
|
+
|
|
|
+const checkData = ref([
|
|
|
+ { label: '年卡', value: 0 },
|
|
|
+ { label: '普通票', value: 0 },
|
|
|
+ { label: '优惠票', value: 0 }
|
|
|
+])
|
|
|
+
|
|
|
+const incomeData = ref({
|
|
|
+ total: 0,
|
|
|
+ details: [
|
|
|
+ { label: '线上收入', value: 0 },
|
|
|
+ { label: '线下收入', value: 0 }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+// 计算总数的方法
|
|
|
+const getTotalOnline = () => {
|
|
|
+ return onlineData.value.reduce((sum, item) => sum + item.value, 0)
|
|
|
+}
|
|
|
+
|
|
|
+const getTotalOffline = () => {
|
|
|
+ return offlineData.value.reduce((sum, item) => sum + item.value, 0)
|
|
|
+}
|
|
|
+
|
|
|
+const getTotalCheck = () => {
|
|
|
+ return checkData.value.reduce((sum, item) => sum + item.value, 0)
|
|
|
+}
|
|
|
+
|
|
|
+// 格式化货币
|
|
|
+const formatCurrency = (value) => {
|
|
|
+ return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
|
+}
|
|
|
+
|
|
|
+// 获取百分比
|
|
|
+const getPercentage = (value, total) => {
|
|
|
+ if (total === 0) return 0
|
|
|
+ return Math.max(10, Math.round((value / total) * 100))
|
|
|
+}
|
|
|
+
|
|
|
+// 根据索引获取颜色
|
|
|
+const getColorByIndex = (index) => {
|
|
|
+ const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399']
|
|
|
+ return colors[index % colors.length]
|
|
|
+}
|
|
|
+
|
|
|
+// 获取统计数据
|
|
|
+const fetchData = async () => {
|
|
|
+ try {
|
|
|
+ const date = dayjs(selectedDate.value).format('YYYY-MM-DD')
|
|
|
+ // 这里先使用模拟数据
|
|
|
+ const mockData = {
|
|
|
+ online: {
|
|
|
+ miniProgram: 150,
|
|
|
+ douyin: 200,
|
|
|
+ meituan: 180,
|
|
|
+ ctrip: 120
|
|
|
+ },
|
|
|
+ offline: {
|
|
|
+ window1: 300,
|
|
|
+ window2: 250
|
|
|
+ },
|
|
|
+ check: {
|
|
|
+ yearCard: 50,
|
|
|
+ normal: 800,
|
|
|
+ discount: 200
|
|
|
+ },
|
|
|
+ income: {
|
|
|
+ total: 50000,
|
|
|
+ online: 30000,
|
|
|
+ offline: 20000
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新数据
|
|
|
+ onlineData.value = [
|
|
|
+ { label: '小程序', value: mockData.online.miniProgram },
|
|
|
+ { label: '抖音', value: mockData.online.douyin },
|
|
|
+ { label: '美团', value: mockData.online.meituan },
|
|
|
+ { label: '携程', value: mockData.online.ctrip }
|
|
|
+ ]
|
|
|
+
|
|
|
+ offlineData.value = [
|
|
|
+ { label: '窗口1', value: mockData.offline.window1 },
|
|
|
+ { label: '窗口2', value: mockData.offline.window2 }
|
|
|
+ ]
|
|
|
+
|
|
|
+ checkData.value = [
|
|
|
+ { label: '年卡', value: mockData.check.yearCard },
|
|
|
+ { label: '普通票', value: mockData.check.normal },
|
|
|
+ { label: '优惠票', value: mockData.check.discount }
|
|
|
+ ]
|
|
|
+
|
|
|
+ incomeData.value = {
|
|
|
+ total: mockData.income.total,
|
|
|
+ details: [
|
|
|
+ { label: '线上收入', value: mockData.income.online },
|
|
|
+ { label: '线下收入', value: mockData.income.offline }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取数据失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleDateChange = () => {
|
|
|
+ fetchData()
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ fetchData()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+/* 整体容器样式 */
|
|
|
+.statistics-container {
|
|
|
+ padding: 24px;
|
|
|
+ max-width: 1280px;
|
|
|
+ margin: 0 auto;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ min-height: 100vh;
|
|
|
+}
|
|
|
+
|
|
|
+/* 页面标题 */
|
|
|
+.page-title {
|
|
|
+ font-size: 28px;
|
|
|
+ color: #303133;
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ font-weight: 600;
|
|
|
+ position: relative;
|
|
|
+ padding-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.page-title::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ width: 80px;
|
|
|
+ height: 3px;
|
|
|
+ background: linear-gradient(90deg, #409EFF, #67C23A);
|
|
|
+ border-radius: 3px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 日期选择器 */
|
|
|
+.date-selector-card {
|
|
|
+ margin-bottom: 24px;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
|
+}
|
|
|
+
|
|
|
+.date-selector-wrapper {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.date-label {
|
|
|
+ margin-right: 10px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #606266;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.date-picker {
|
|
|
+ width: 220px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 统计卡片网格 */
|
|
|
+.statistics-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
|
|
|
+ gap: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 统计卡片通用样式 */
|
|
|
+.statistics-card {
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
|
+ transition: transform 0.3s, box-shadow 0.3s;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.statistics-card:hover {
|
|
|
+ transform: translateY(-5px);
|
|
|
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
|
+}
|
|
|
+
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 16px 20px;
|
|
|
+ /*border-bottom: 1px solid #EBEEF5;*/
|
|
|
+}
|
|
|
+
|
|
|
+.card-title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
+.card-content {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 数据部分通用样式 */
|
|
|
+.data-section {
|
|
|
+ margin-bottom: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.data-section:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ /* gap: 8px; */
|
|
|
+}
|
|
|
+
|
|
|
+.data-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ /* gap: 12px; */
|
|
|
+}
|
|
|
+
|
|
|
+/* 只展示需要修改的部分 */
|
|
|
+.data-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 14px 0;
|
|
|
+ /* border-bottom: 1px dashed #EBEEF5; */
|
|
|
+}
|
|
|
+
|
|
|
+.data-item + .data-item {
|
|
|
+ border-top: 1px dashed #EBEEF5;
|
|
|
+}
|
|
|
+
|
|
|
+/* 修改总计项样式,使其独立于 data-item */
|
|
|
+.total-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-top: 8px;
|
|
|
+ padding-top: 12px;
|
|
|
+ padding-bottom: 8px;
|
|
|
+ border-top: 1px solid #EBEEF5;
|
|
|
+}
|
|
|
+
|
|
|
+.label {
|
|
|
+ color: #606266;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.value {
|
|
|
+ font-weight: 500;
|
|
|
+ color: #303133;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.highlight-value {
|
|
|
+ color: #409EFF;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.total-value {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
+/* 售票卡片特殊样式 */
|
|
|
+.sales-card {
|
|
|
+ border-top: 4px solid #67C23A;
|
|
|
+}
|
|
|
+
|
|
|
+/* 检票卡片特殊样式 */
|
|
|
+.check-card {
|
|
|
+ border-top: 4px solid #E6A23C;
|
|
|
+}
|
|
|
+
|
|
|
+.check-data-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.check-chart {
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-placeholder {
|
|
|
+ display: flex;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 20px;
|
|
|
+ overflow: hidden;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-circle {
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: white;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.label-with-color {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.color-dot {
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: inline-block;
|
|
|
+}
|
|
|
+
|
|
|
+/* 收入卡片特殊样式 */
|
|
|
+.income-card {
|
|
|
+ border-top: 4px solid #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.total-income {
|
|
|
+ text-align: center;
|
|
|
+ padding: 24px 0;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ background: linear-gradient(135deg, #ecf5ff, #f0f9eb);
|
|
|
+ border-radius: 8px;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.income-icon {
|
|
|
+ font-size: 24px;
|
|
|
+ color: #409EFF;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.income-amount {
|
|
|
+ font-size: 32px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #409EFF;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.income-label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+
|
|
|
+.income-details {
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.income-value {
|
|
|
+ color: #67C23A;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.income-ratio-bar {
|
|
|
+ height: 24px;
|
|
|
+ display: flex;
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+ margin: 16px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.ratio-segment {
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: white;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ transition: width 0.5s;
|
|
|
+}
|
|
|
+
|
|
|
+.online-segment {
|
|
|
+ background-color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.offline-segment {
|
|
|
+ background-color: #67C23A;
|
|
|
+}
|
|
|
+
|
|
|
+.ratio-legend {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 24px;
|
|
|
+ margin-top: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.legend-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+
|
|
|
+.online-dot {
|
|
|
+ background-color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.offline-dot {
|
|
|
+ background-color: #67C23A;
|
|
|
+}
|
|
|
+
|
|
|
+/* 响应式设计 */
|
|
|
+@media (max-width: 1200px) {
|
|
|
+ .statistics-grid {
|
|
|
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .statistics-container {
|
|
|
+ padding: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .statistics-grid {
|
|
|
+ grid-template-columns: 1fr;
|
|
|
+ gap: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-title {
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .income-amount {
|
|
|
+ font-size: 28px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|