994 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			994 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						||
  <view class="statistics-container">
 | 
						||
    <!-- 移动设备顶部状态栏 -->
 | 
						||
    <view class="top_bar flex w-full" v-if="isMobile">
 | 
						||
      <view class="chat-header">
 | 
						||
        <view class="header-left" @click="goBack">
 | 
						||
          <i class="fas fa-arrow-left"></i>
 | 
						||
        </view>
 | 
						||
        <view class="header-title">考勤统计</view>
 | 
						||
        <view class="header-right" @click="showMoreOptions">
 | 
						||
          <i class="fas fa-ellipsis-v"></i>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
    </view>
 | 
						||
    
 | 
						||
    <!-- 浏览器环境下的导航栏 -->
 | 
						||
    <view class="chat-header" v-else>
 | 
						||
      <view class="header-left" @click="goBack">
 | 
						||
        <i class="fas fa-arrow-left"></i>
 | 
						||
      </view>
 | 
						||
      <view class="header-title">考勤统计</view>
 | 
						||
      <view class="header-right" @click="showMoreOptions">
 | 
						||
        <i class="fas fa-ellipsis-v"></i>
 | 
						||
      </view>
 | 
						||
    </view>
 | 
						||
 | 
						||
    <!-- 页面内容 -->
 | 
						||
    <scroll-view scroll-y class="statistics-content">
 | 
						||
 | 
						||
    <!-- 导出报表 -->
 | 
						||
    <view class="export-card card">
 | 
						||
        <view class="export-title">导出报表</view>
 | 
						||
        <view class="exports">
 | 
						||
          <view class="btn-export" @click="exportReport"> 导出 </view>
 | 
						||
          <i class="fas fa-angle-right" style="font-size: 20rpx; color: var(--tab-inactive);position: relative;top: 4rpx;"></i>
 | 
						||
        </view>
 | 
						||
    </view>
 | 
						||
 | 
						||
    <!-- 统计数据 -->
 | 
						||
    <view class="stats-card card">
 | 
						||
      <!-- Tabbar -->
 | 
						||
      <view class="stat-tabs">
 | 
						||
        <view 
 | 
						||
          v-for="t in tabs" 
 | 
						||
          :key="t.value" 
 | 
						||
          class="stat-tab"
 | 
						||
          :class="{ active: statTab === t.value }"
 | 
						||
          @click="statTab = t.value"
 | 
						||
          >{{ t.label }}</view
 | 
						||
        >
 | 
						||
      </view>
 | 
						||
 | 
						||
      <!-- 日统计(显示日历) -->
 | 
						||
      <view v-if="statTab === 'day'" class="tab-content">
 | 
						||
        <view class="calendar">
 | 
						||
          <view class="cal-title">
 | 
						||
            {{ today.getFullYear() }}年{{ today.getMonth() + 1 }}月
 | 
						||
          </view>
 | 
						||
          <view class="cal-week-head">
 | 
						||
            <text
 | 
						||
              v-for="w in ['日', '一', '二', '三', '四', '五', '六']"
 | 
						||
              :key="w"
 | 
						||
              >{{ w }}</text
 | 
						||
            >
 | 
						||
          </view>
 | 
						||
          <view class="cal-body">
 | 
						||
            <view
 | 
						||
              v-for="(week, weekIndex) in calendarWeeks"
 | 
						||
              :key="weekIndex"
 | 
						||
              class="cal-row"
 | 
						||
            >
 | 
						||
              <view
 | 
						||
                v-for="day in week"
 | 
						||
                :key="day.key"
 | 
						||
                class="cal-cell"
 | 
						||
                :class="{
 | 
						||
                  empty: day.empty,
 | 
						||
                  selected:
 | 
						||
                    !day.empty && calendarSelected.includes(day.fullDate),
 | 
						||
                }"
 | 
						||
                @click="
 | 
						||
                  !day.empty &&
 | 
						||
                    selectDay({
 | 
						||
                      fullDate: day.fullDate,
 | 
						||
                      day: day.day,
 | 
						||
                      month: day.month,
 | 
						||
                      year: day.year,
 | 
						||
                    })
 | 
						||
                "
 | 
						||
                >{{ day.empty ? "" : day.day }}</view
 | 
						||
              >
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
        
 | 
						||
        <!-- 选中日期的数据显示卡片 -->
 | 
						||
        <view v-if="selectedDayInfo" class="day-data-card">
 | 
						||
          <view class="day-data-header">
 | 
						||
            <view class="day-data-title">
 | 
						||
              <i class="fas fa-calendar-day"></i>
 | 
						||
              <text>{{ selectedDayInfo.year }}年{{ selectedDayInfo.month }}月{{ selectedDayInfo.day }}日</text>
 | 
						||
            </view>
 | 
						||
            <view class="day-data-subtitle">考勤详情</view>
 | 
						||
          </view>
 | 
						||
          
 | 
						||
          <view class="day-data-content">
 | 
						||
            <view 
 | 
						||
              class="day-data-item"
 | 
						||
              v-for="(item, index) in dailyStats"
 | 
						||
              :key="index"
 | 
						||
            >
 | 
						||
              <view class="day-data-icon" :class="item.status || 'default'">
 | 
						||
                <i :class="item.icon"></i>
 | 
						||
              </view>
 | 
						||
              <view class="day-data-info">
 | 
						||
                <view class="day-data-label">{{ item.title }}</view>
 | 
						||
                <view class="day-data-value" :class="item.status || 'default'">
 | 
						||
                  {{ item.value }}
 | 
						||
                </view>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
 | 
						||
      <!-- 周统计 -->
 | 
						||
      <view v-if="statTab === 'week'" class="tab-content">
 | 
						||
        <view class="bar-tabs">
 | 
						||
          <view 
 | 
						||
            class="bar-tab"
 | 
						||
            v-for="(item, index) in weekTabs"
 | 
						||
            :key="item.value"
 | 
						||
            :class="{ active: weekTab === item.value }"
 | 
						||
            @click="weekTab = item.value"
 | 
						||
            >{{ item.label }}</view
 | 
						||
          >
 | 
						||
        </view>
 | 
						||
        <view class="count-list">
 | 
						||
          <view
 | 
						||
            class="count-item"
 | 
						||
            v-for="(item, idx) in (weekStats[weekTab] || [])"
 | 
						||
            :key="idx"
 | 
						||
          >
 | 
						||
            <view class="c-value">{{ item.value }}</view>
 | 
						||
            <view class="c-title">{{ item.title }}</view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
 | 
						||
      <!-- 月统计 -->
 | 
						||
      <view v-if="statTab === 'month'" class="tab-content">
 | 
						||
        <view class="month-grid">
 | 
						||
              <view 
 | 
						||
            class="month-item"
 | 
						||
            v-for="(item, index) in monthTabs"
 | 
						||
                :key="item.value"
 | 
						||
            :class="{ active: monthTab === item.value }"
 | 
						||
                @click="monthTab = item.value"
 | 
						||
          >
 | 
						||
            <view class="month-label">{{ item.label }}</view>
 | 
						||
            </view>
 | 
						||
        </view>
 | 
						||
        <view class="count-list">
 | 
						||
          <view
 | 
						||
            class="count-item"
 | 
						||
            v-for="(item, idx) in (monthStats[monthTab] || [])"
 | 
						||
            :key="idx"
 | 
						||
          >
 | 
						||
            <view class="c-value">{{ item.value }}</view>
 | 
						||
            <view class="c-title">{{ item.title }}</view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
    </view>
 | 
						||
    </scroll-view>
 | 
						||
  </view>
 | 
						||
</template>
 | 
						||
 | 
						||
<script>
 | 
						||
export default {
 | 
						||
  data() {
 | 
						||
    const today = new Date();
 | 
						||
    return {
 | 
						||
      today: today,
 | 
						||
      tabs: [
 | 
						||
        { label: "日统计", value: "day" },
 | 
						||
        { label: "周统计", value: "week" },
 | 
						||
        { label: "月统计", value: "month" },
 | 
						||
      ],
 | 
						||
      statTab: "day",
 | 
						||
      calendarSelected: [
 | 
						||
        `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(
 | 
						||
          2,
 | 
						||
          "0"
 | 
						||
        )}-${String(today.getDate()).padStart(2, "0")}`,
 | 
						||
      ],
 | 
						||
      weekTabs: [
 | 
						||
        { label: "第1周", value: "1" },
 | 
						||
        { label: "第2周", value: "2" },
 | 
						||
        { label: "第3周", value: "3" },
 | 
						||
        { label: "第4周", value: "4" },
 | 
						||
      ],
 | 
						||
      weekTab: "1",
 | 
						||
      monthTabs: Array.from({ length: 12 }, (_, i) => ({
 | 
						||
        label: `${i + 1}月`,
 | 
						||
        value: String(i + 1),
 | 
						||
      })),
 | 
						||
      monthTab: String(today.getMonth() + 1),
 | 
						||
      baseStat: [
 | 
						||
        { title: "平均工时", value: "7.8h" },
 | 
						||
        { title: "迟到次数", value: "1" },
 | 
						||
        { title: "早退次数", value: "0" },
 | 
						||
        { title: "缺卡次数", value: "0" },
 | 
						||
        { title: "旷工次数", value: "0" },
 | 
						||
        { title: "外勤次数", value: "2" },
 | 
						||
        { title: "加班时长", value: "4h" },
 | 
						||
        { title: "调休时长", value: "2h" },
 | 
						||
      ],
 | 
						||
      selectedDayData: null, // 选中日期的数据
 | 
						||
      selectedDayInfo: null, // 选中日期的基本信息
 | 
						||
    };
 | 
						||
  },
 | 
						||
  computed: {
 | 
						||
    weekStats() {
 | 
						||
      try {
 | 
						||
        return {
 | 
						||
          "1": this.baseStat || [],
 | 
						||
          "2": (this.baseStat || []).map((item, i) =>
 | 
						||
            i === 1 ? { ...item, value: "0" } : item
 | 
						||
          ),
 | 
						||
          "3": (this.baseStat || []).map((item, i) =>
 | 
						||
            i === 3 ? { ...item, value: "1" } : item
 | 
						||
          ),
 | 
						||
          "4": (this.baseStat || []).map((item, i) =>
 | 
						||
            i === 5 ? { ...item, value: "3" } : item
 | 
						||
          ),
 | 
						||
        };
 | 
						||
      } catch (error) {
 | 
						||
        console.error('周统计数据生成错误:', error);
 | 
						||
        return {};
 | 
						||
      }
 | 
						||
    },
 | 
						||
    monthStats() {
 | 
						||
      try {
 | 
						||
        const stats = {};
 | 
						||
        (this.monthTabs || []).forEach((_, i) => {
 | 
						||
          stats[String(i + 1)] = (this.baseStat || []).map((item) => ({
 | 
						||
            ...item,
 | 
						||
            value: String(
 | 
						||
              Math.floor(Math.random() * 3) +
 | 
						||
                (item.value.includes("h") ? "h" : "")
 | 
						||
            ),
 | 
						||
          }));
 | 
						||
        });
 | 
						||
        return stats;
 | 
						||
      } catch (error) {
 | 
						||
        console.error('月统计数据生成错误:', error);
 | 
						||
        return {};
 | 
						||
      }
 | 
						||
    },
 | 
						||
    // 日历相关计算属性
 | 
						||
    days() {
 | 
						||
      const d = new Date(
 | 
						||
        this.today.getFullYear(),
 | 
						||
        this.today.getMonth() + 1,
 | 
						||
        0
 | 
						||
      ).getDate();
 | 
						||
      return Array.from({ length: d }, (_, i) => i + 1);
 | 
						||
    },
 | 
						||
    firstDay() {
 | 
						||
      return new Date(
 | 
						||
        this.today.getFullYear(),
 | 
						||
        this.today.getMonth(),
 | 
						||
        1
 | 
						||
      ).getDay();
 | 
						||
    },
 | 
						||
    calendarWeeks() {
 | 
						||
      try {
 | 
						||
        const year = this.today.getFullYear();
 | 
						||
        const month = this.today.getMonth();
 | 
						||
        const firstDay = new Date(year, month, 1).getDay();
 | 
						||
        const daysInMonth = new Date(year, month + 1, 0).getDate();
 | 
						||
 | 
						||
        const weeks = [];
 | 
						||
        let currentWeek = [];
 | 
						||
 | 
						||
        // 添加空白日期(上个月的末尾几天)
 | 
						||
        for (let i = 0; i < firstDay; i++) {
 | 
						||
          currentWeek.push({
 | 
						||
            key: `empty-${i}`,
 | 
						||
            empty: true,
 | 
						||
            day: "",
 | 
						||
            fullDate: "",
 | 
						||
            month: month,
 | 
						||
            year: year,
 | 
						||
          });
 | 
						||
        }
 | 
						||
 | 
						||
        // 添加当前月的日期
 | 
						||
        for (let day = 1; day <= daysInMonth; day++) {
 | 
						||
          const fullDate = `${year}-${String(month + 1).padStart(
 | 
						||
            2,
 | 
						||
            "0"
 | 
						||
          )}-${String(day).padStart(2, "0")}`;
 | 
						||
          currentWeek.push({
 | 
						||
            key: `day-${day}`,
 | 
						||
            empty: false,
 | 
						||
            day: day,
 | 
						||
            fullDate: fullDate,
 | 
						||
            month: month + 1,
 | 
						||
            year: year,
 | 
						||
          });
 | 
						||
 | 
						||
          // 如果一周满了(7天),开始新的一周
 | 
						||
          if (currentWeek.length === 7) {
 | 
						||
            weeks.push([...currentWeek]);
 | 
						||
            currentWeek = [];
 | 
						||
          }
 | 
						||
        }
 | 
						||
 | 
						||
        // 如果最后一周不满7天,用空白日期填充
 | 
						||
        while (currentWeek.length > 0 && currentWeek.length < 7) {
 | 
						||
          currentWeek.push({
 | 
						||
            key: `empty-end-${currentWeek.length}`,
 | 
						||
            empty: true,
 | 
						||
            day: "",
 | 
						||
            fullDate: "",
 | 
						||
            month: month,
 | 
						||
            year: year,
 | 
						||
          });
 | 
						||
        }
 | 
						||
 | 
						||
        // 如果还有未完成的周,添加到结果中
 | 
						||
        if (currentWeek.length > 0) {
 | 
						||
          weeks.push(currentWeek);
 | 
						||
        }
 | 
						||
 | 
						||
        return weeks;
 | 
						||
      } catch (error) {
 | 
						||
        console.error('日历生成错误:', error);
 | 
						||
        return [];
 | 
						||
      }
 | 
						||
    },
 | 
						||
    isMobile() {
 | 
						||
      return getApp().globalData.isMobile;
 | 
						||
    },
 | 
						||
    // 生成每日数据
 | 
						||
    dailyStats() {
 | 
						||
      if (!this.selectedDayInfo) return [];
 | 
						||
      
 | 
						||
      const { year, month, day } = this.selectedDayInfo;
 | 
						||
      const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
 | 
						||
      
 | 
						||
      // 模拟不同日期的不同数据
 | 
						||
      const randomSeed = year * 10000 + month * 100 + day;
 | 
						||
      const random = (seed) => {
 | 
						||
        const x = Math.sin(seed) * 10000;
 | 
						||
        return x - Math.floor(x);
 | 
						||
      };
 | 
						||
      
 | 
						||
      return [
 | 
						||
        { 
 | 
						||
          title: "上班时间", 
 | 
						||
          value: `${String(Math.floor(random(randomSeed) * 2) + 8).padStart(2, '0')}:${String(Math.floor(random(randomSeed + 1) * 60)).padStart(2, '0')}`,
 | 
						||
          icon: "fas fa-clock"
 | 
						||
        },
 | 
						||
        { 
 | 
						||
          title: "下班时间", 
 | 
						||
          value: `${String(Math.floor(random(randomSeed + 2) * 2) + 17).padStart(2, '0')}:${String(Math.floor(random(randomSeed + 3) * 60)).padStart(2, '0')}`,
 | 
						||
          icon: "fas fa-clock"
 | 
						||
        },
 | 
						||
        { 
 | 
						||
          title: "迟到状态", 
 | 
						||
          value: random(randomSeed + 5) > 0.8 ? "迟到" : "正常",
 | 
						||
          icon: random(randomSeed + 5) > 0.8 ? "fas fa-exclamation-triangle" : "fas fa-check-circle",
 | 
						||
          status: random(randomSeed + 5) > 0.8 ? "warning" : "success"
 | 
						||
        },
 | 
						||
        { 
 | 
						||
          title: "早退状态", 
 | 
						||
          value: random(randomSeed + 6) > 0.9 ? "早退" : "正常",
 | 
						||
          icon: random(randomSeed + 6) > 0.9 ? "fas fa-exclamation-triangle" : "fas fa-check-circle",
 | 
						||
          status: random(randomSeed + 6) > 0.9 ? "warning" : "success"
 | 
						||
        },
 | 
						||
        { 
 | 
						||
          title: "工作时长", 
 | 
						||
          value: `${(random(randomSeed + 4) * 4 + 6).toFixed(1)}h`,
 | 
						||
          icon: "fas fa-hourglass-half"
 | 
						||
        },
 | 
						||
        { 
 | 
						||
          title: "外勤次数", 
 | 
						||
          value: Math.floor(random(randomSeed + 7) * 3).toString(),
 | 
						||
          icon: "fas fa-map-marker-alt"
 | 
						||
        },
 | 
						||
        { 
 | 
						||
          title: "加班时长", 
 | 
						||
          value: random(randomSeed + 8) > 0.6 ? `${(random(randomSeed + 8) * 3).toFixed(1)}h` : "0h",
 | 
						||
          icon: "fas fa-moon"
 | 
						||
        },
 | 
						||
        { 
 | 
						||
          title: "调休时长", 
 | 
						||
          value: random(randomSeed + 9) > 0.7 ? `${(random(randomSeed + 9) * 2).toFixed(1)}h` : "0h",
 | 
						||
          icon: "fas fa-calendar-alt"
 | 
						||
        },
 | 
						||
      ];
 | 
						||
    },
 | 
						||
  },
 | 
						||
  mounted() {
 | 
						||
    console.log('统计页面初始化');
 | 
						||
    console.log('当前月份:', this.today.getMonth() + 1);
 | 
						||
    console.log('基础数据:', this.baseStat);
 | 
						||
    console.log('周标签:', this.weekTabs);
 | 
						||
    console.log('月标签:', this.monthTabs);
 | 
						||
    console.log('当前周标签值:', this.weekTab, typeof this.weekTab);
 | 
						||
    console.log('当前月标签值:', this.monthTab, typeof this.monthTab);
 | 
						||
    console.log('周统计数据:', this.weekStats);
 | 
						||
    console.log('月统计数据:', this.monthStats);
 | 
						||
    console.log('周统计键:', Object.keys(this.weekStats));
 | 
						||
    console.log('月统计键:', Object.keys(this.monthStats));
 | 
						||
    console.log('周统计访问测试:', this.weekStats[this.weekTab]);
 | 
						||
    console.log('月统计访问测试:', this.monthStats[this.monthTab]);
 | 
						||
    
 | 
						||
    // 初始化默认选中今天
 | 
						||
    this.selectedDayInfo = {
 | 
						||
      year: this.today.getFullYear(),
 | 
						||
      month: this.today.getMonth() + 1,
 | 
						||
      day: this.today.getDate(),
 | 
						||
      fullDate: `${this.today.getFullYear()}-${String(this.today.getMonth() + 1).padStart(2, '0')}-${String(this.today.getDate()).padStart(2, '0')}`
 | 
						||
    };
 | 
						||
    console.log('默认选中今天:', this.selectedDayInfo);
 | 
						||
  },
 | 
						||
  methods: {
 | 
						||
    selectDay(day) {
 | 
						||
      this.calendarSelected = [day.fullDate];
 | 
						||
      this.selectedDayInfo = {
 | 
						||
        year: day.year,
 | 
						||
        month: day.month,
 | 
						||
        day: day.day,
 | 
						||
        fullDate: day.fullDate
 | 
						||
      };
 | 
						||
      console.log('选择日期:', day);
 | 
						||
      console.log('选中日期信息:', this.selectedDayInfo);
 | 
						||
    },
 | 
						||
    exportReport() {
 | 
						||
      uni.showToast({ title: "导出功能暂未开放" });
 | 
						||
    },
 | 
						||
    goBack() {
 | 
						||
      uni.navigateBack();
 | 
						||
    },
 | 
						||
    showMoreOptions() {
 | 
						||
      uni.showActionSheet({
 | 
						||
        itemList: ['刷新数据', '导出报表', '设置'],
 | 
						||
        success: (res) => {
 | 
						||
          if (res.tapIndex === 0) {
 | 
						||
            uni.showToast({ title: '刷新成功' });
 | 
						||
          } else if (res.tapIndex === 1) {
 | 
						||
            this.exportReport();
 | 
						||
          } else if (res.tapIndex === 2) {
 | 
						||
            uni.showToast({ title: '设置功能暂未开放' });
 | 
						||
          }
 | 
						||
        }
 | 
						||
      });
 | 
						||
    },
 | 
						||
  },
 | 
						||
};
 | 
						||
</script>
 | 
						||
 | 
						||
<style lang="scss" scoped>
 | 
						||
/* 移动设备顶部状态栏 */
 | 
						||
.top_bar {
 | 
						||
  background: var(--gradient-primary);
 | 
						||
  box-shadow: var(--shadow-lg);
 | 
						||
  z-index: 9999;
 | 
						||
  position: fixed;
 | 
						||
  top: 0;
 | 
						||
  left: 0;
 | 
						||
  right: 0;
 | 
						||
  height: calc(var(--status-bar-height) + 88rpx);
 | 
						||
  display: flex;
 | 
						||
  align-items: flex-end;
 | 
						||
  padding-top: var(--status-bar-height);
 | 
						||
  box-sizing: border-box;
 | 
						||
}
 | 
						||
 | 
						||
/* 支持安全区域的设备 */
 | 
						||
@supports (padding: max(0px)) {
 | 
						||
  .top_bar {
 | 
						||
    height: calc(var(--status-bar-height) + 88rpx + env(safe-area-inset-top));
 | 
						||
    padding-top: calc(var(--status-bar-height) + env(safe-area-inset-top));
 | 
						||
  }
 | 
						||
  
 | 
						||
  .top_bar + .statistics-content {
 | 
						||
    margin-top: calc(var(--status-bar-height) + 88rpx + env(safe-area-inset-top));
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
/* 顶部导航栏 */
 | 
						||
.chat-header {
 | 
						||
  display: flex;
 | 
						||
  justify-content: space-between;
 | 
						||
  align-items: center;
 | 
						||
  height: 88rpx;
 | 
						||
  background-color: var(--surface);
 | 
						||
  border-bottom: 1rpx solid var(--border);
 | 
						||
  padding: 0 20rpx;
 | 
						||
  box-sizing: border-box;
 | 
						||
  box-shadow: var(--shadow);
 | 
						||
}
 | 
						||
 | 
						||
/* 移动设备下的导航栏样式 */
 | 
						||
.top_bar .chat-header {
 | 
						||
  background: transparent;
 | 
						||
  border-bottom: none;
 | 
						||
  box-shadow: none;
 | 
						||
  width: 100%;
 | 
						||
  height: 88rpx;
 | 
						||
  padding: 0 20rpx;
 | 
						||
  box-sizing: border-box;
 | 
						||
}
 | 
						||
 | 
						||
.top_bar .header-title {
 | 
						||
  color: var(--white);
 | 
						||
  font-weight: 600;
 | 
						||
  font-size: 36rpx;
 | 
						||
}
 | 
						||
 | 
						||
.top_bar .header-left i,
 | 
						||
.top_bar .header-right i {
 | 
						||
  color: var(--white);
 | 
						||
  font-size: 40rpx;
 | 
						||
}
 | 
						||
 | 
						||
.header-left,
 | 
						||
.header-right {
 | 
						||
  width: 80rpx;
 | 
						||
  height: 88rpx;
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  justify-content: center;
 | 
						||
  transition: background-color 0.2s ease;
 | 
						||
}
 | 
						||
 | 
						||
/* 移动设备下的按钮悬停效果 */
 | 
						||
.top_bar .header-left:active,
 | 
						||
.top_bar .header-right:active {
 | 
						||
  background-color: rgba(255, 255, 255, 0.2);
 | 
						||
  border-radius: 8rpx;
 | 
						||
}
 | 
						||
 | 
						||
.header-title {
 | 
						||
  font-size: 32rpx;
 | 
						||
  font-weight: 600;
 | 
						||
  color: var(--title-color);
 | 
						||
}
 | 
						||
 | 
						||
.header-icon {
 | 
						||
  font-size: 36rpx;
 | 
						||
  color: var(--text-color);
 | 
						||
  padding: 10rpx;
 | 
						||
  transition: all 0.3s ease;
 | 
						||
}
 | 
						||
 | 
						||
.header-icon:active {
 | 
						||
  background: var(--hover-bg);
 | 
						||
  transform: scale(0.95);
 | 
						||
  border-radius: 8rpx;
 | 
						||
}
 | 
						||
 | 
						||
/* 移动设备下为内容添加顶部间距 */
 | 
						||
.top_bar + .statistics-content {
 | 
						||
  margin-top: calc(var(--status-bar-height) + 88rpx);
 | 
						||
}
 | 
						||
 | 
						||
/* 浏览器环境下为内容添加顶部间距 */
 | 
						||
.chat-header + .statistics-content {
 | 
						||
  margin-top: calc(var(--status-bar-height) + 88rpx);
 | 
						||
}
 | 
						||
 | 
						||
.statistics-container {
 | 
						||
  background: #f7f8fa;
 | 
						||
  min-height: 100vh;
 | 
						||
}
 | 
						||
 | 
						||
.statistics-content {
 | 
						||
  padding: 32rpx 0;
 | 
						||
  min-height: calc(100vh - 88rpx);
 | 
						||
}
 | 
						||
 | 
						||
  .card {
 | 
						||
    background: #fff;
 | 
						||
    border-radius: 16rpx;
 | 
						||
  box-shadow: 0 4rpx 16rpx 0 rgba(0, 0, 0, 0.04);
 | 
						||
    margin: 0 32rpx 32rpx;
 | 
						||
    padding: 32rpx;
 | 
						||
}
 | 
						||
.export-card {
 | 
						||
  display: flex;
 | 
						||
  justify-content: space-between;
 | 
						||
  align-items: center;
 | 
						||
  .export-title {
 | 
						||
    font-size: 32rpx;
 | 
						||
    font-weight: 600;
 | 
						||
  }
 | 
						||
  .btn-export {
 | 
						||
    // background: #3c9cff;
 | 
						||
    color: var(--tab-inactive);
 | 
						||
    font-size: 28rpx;
 | 
						||
    border: none;
 | 
						||
    // padding: 4rpx 40rpx;
 | 
						||
    border-radius: 8rpx;
 | 
						||
  }
 | 
						||
 | 
						||
  .exports {
 | 
						||
    display: flex;
 | 
						||
    align-items: center;
 | 
						||
    .btn-export {
 | 
						||
      margin-right: 16rpx;
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
.stats-card {
 | 
						||
  .stat-tabs {
 | 
						||
    display: flex;
 | 
						||
    margin-bottom: 32rpx;
 | 
						||
    .stat-tab {
 | 
						||
      flex: 1;
 | 
						||
      text-align: center;
 | 
						||
      font-size: 28rpx;
 | 
						||
      color: var(--text-muted);
 | 
						||
      padding-bottom: 16rpx;
 | 
						||
      border-bottom: 4rpx solid transparent;
 | 
						||
      transition: all 0.2s;
 | 
						||
      &.active {
 | 
						||
        color: var(--primary-color);
 | 
						||
        font-weight: 600;
 | 
						||
        border-color: var(--primary-color);
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
  .tab-content {
 | 
						||
    margin-top: 16rpx;
 | 
						||
  }
 | 
						||
  // 月统计网格布局
 | 
						||
  .month-grid {
 | 
						||
    display: grid;
 | 
						||
    grid-template-columns: repeat(4, 1fr);
 | 
						||
    gap: 12rpx;
 | 
						||
    margin-bottom: 24rpx;
 | 
						||
    
 | 
						||
    .month-item {
 | 
						||
      background: var(--gray-lighter);
 | 
						||
      border-radius: 12rpx;
 | 
						||
      padding: 20rpx 12rpx;
 | 
						||
      text-align: center;
 | 
						||
      border: 1rpx solid var(--border-light);
 | 
						||
      transition: all 0.3s ease;
 | 
						||
      cursor: pointer;
 | 
						||
      
 | 
						||
      .month-label {
 | 
						||
        font-size: 26rpx;
 | 
						||
        color: var(--text-secondary);
 | 
						||
        font-weight: 500;
 | 
						||
      }
 | 
						||
      
 | 
						||
      &.active {
 | 
						||
        background: var(--primary-color);
 | 
						||
        border-color: var(--primary-color);
 | 
						||
        box-shadow: var(--shadow-md);
 | 
						||
        transform: translateY(-2rpx);
 | 
						||
        
 | 
						||
        .month-label {
 | 
						||
          color: var(--white);
 | 
						||
          font-weight: 600;
 | 
						||
        }
 | 
						||
      }
 | 
						||
      
 | 
						||
      &:not(.active):active {
 | 
						||
        background: var(--primary-light);
 | 
						||
        transform: scale(0.98);
 | 
						||
        
 | 
						||
        .month-label {
 | 
						||
          color: var(--white);
 | 
						||
        }
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  .bar-tabs {
 | 
						||
    display: flex;
 | 
						||
    background: var(--gray-lighter);
 | 
						||
    border-radius: 12rpx;
 | 
						||
    padding: 6rpx;
 | 
						||
    margin-bottom: 24rpx;
 | 
						||
    position: relative;
 | 
						||
 | 
						||
    .bar-tab {
 | 
						||
      flex: 1;
 | 
						||
      text-align: center;
 | 
						||
      font-size: 28rpx;
 | 
						||
      color: var(--text-secondary);
 | 
						||
      padding: 16rpx 12rpx;
 | 
						||
      border-radius: 8rpx;
 | 
						||
      margin: 0 2rpx;
 | 
						||
      background: transparent;
 | 
						||
      transition: all 0.3s ease;
 | 
						||
      position: relative;
 | 
						||
      font-weight: 500;
 | 
						||
 | 
						||
      &.active {
 | 
						||
        color: var(--primary-color);
 | 
						||
        background: var(--surface);
 | 
						||
        font-weight: 600;
 | 
						||
        box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 | 
						||
        transform: translateY(-1rpx);
 | 
						||
      }
 | 
						||
 | 
						||
      &:not(.active):active {
 | 
						||
        background: rgba(60, 156, 255, 0.1);
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  .bar-tabs-scroll {
 | 
						||
    background: #f8f9fa;
 | 
						||
    border-radius: 12rpx;
 | 
						||
    padding: 6rpx;
 | 
						||
    margin-bottom: 24rpx;
 | 
						||
 | 
						||
    .bar-scroll {
 | 
						||
    white-space: nowrap;
 | 
						||
 | 
						||
    .bar-tab {
 | 
						||
      display: inline-block;
 | 
						||
        min-width: 120rpx;
 | 
						||
        margin: 0 4rpx;
 | 
						||
        padding: 16rpx 20rpx;
 | 
						||
        text-align: center;
 | 
						||
        font-size: 28rpx;
 | 
						||
        color: #666;
 | 
						||
        border-radius: 8rpx;
 | 
						||
        background: transparent;
 | 
						||
        transition: all 0.3s ease;
 | 
						||
        font-weight: 500;
 | 
						||
 | 
						||
        &.active {
 | 
						||
          color: #3c9cff;
 | 
						||
          background: #fff;
 | 
						||
          font-weight: 600;
 | 
						||
          box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 | 
						||
          transform: translateY(-1rpx);
 | 
						||
        }
 | 
						||
 | 
						||
        &:not(.active):active {
 | 
						||
          background: rgba(60, 156, 255, 0.1);
 | 
						||
        }
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
  // 日统计数据显示卡片
 | 
						||
  .day-data-card {
 | 
						||
    margin-top: 24rpx;
 | 
						||
    background: var(--surface);
 | 
						||
    border-radius: 16rpx;
 | 
						||
    box-shadow: var(--shadow-md);
 | 
						||
    overflow: hidden;
 | 
						||
    border: 1rpx solid var(--border);
 | 
						||
    
 | 
						||
    .day-data-header {
 | 
						||
      background: var(--gradient-primary);
 | 
						||
      padding: 32rpx 24rpx;
 | 
						||
      color: var(--white);
 | 
						||
      
 | 
						||
      .day-data-title {
 | 
						||
        display: flex;
 | 
						||
        align-items: center;
 | 
						||
        font-size: 32rpx;
 | 
						||
        font-weight: 600;
 | 
						||
        margin-bottom: 8rpx;
 | 
						||
        color: var(--white);
 | 
						||
        
 | 
						||
        i {
 | 
						||
          margin-right: 12rpx;
 | 
						||
          font-size: 28rpx;
 | 
						||
          color: var(--white);
 | 
						||
        }
 | 
						||
      }
 | 
						||
      
 | 
						||
      .day-data-subtitle {
 | 
						||
        font-size: 24rpx;
 | 
						||
        opacity: 0.9;
 | 
						||
        color: var(--white);
 | 
						||
      }
 | 
						||
    }
 | 
						||
    
 | 
						||
    .day-data-content {
 | 
						||
      padding: 24rpx;
 | 
						||
      background: var(--surface);
 | 
						||
      display: flex;
 | 
						||
      flex-wrap: wrap;
 | 
						||
      justify-content: space-between;
 | 
						||
      
 | 
						||
      .day-data-item {
 | 
						||
        display: flex;
 | 
						||
        align-items: center;
 | 
						||
        padding: 20rpx 16rpx;
 | 
						||
        width: 48%;
 | 
						||
        margin-bottom: 16rpx;
 | 
						||
        background: var(--gray-lighter);
 | 
						||
        border-radius: 12rpx;
 | 
						||
        border: 1rpx solid var(--border-light);
 | 
						||
        box-sizing: border-box;
 | 
						||
        
 | 
						||
        &:nth-child(odd) {
 | 
						||
          margin-right: 2%;
 | 
						||
        }
 | 
						||
        
 | 
						||
        &:nth-child(even) {
 | 
						||
          margin-left: 2%;
 | 
						||
        }
 | 
						||
        
 | 
						||
        .day-data-icon {
 | 
						||
          width: 48rpx;
 | 
						||
          height: 48rpx;
 | 
						||
          border-radius: 50%;
 | 
						||
          display: flex;
 | 
						||
          align-items: center;
 | 
						||
          justify-content: center;
 | 
						||
          margin-right: 12rpx;
 | 
						||
          flex-shrink: 0;
 | 
						||
          
 | 
						||
          i {
 | 
						||
            font-size: 20rpx;
 | 
						||
          }
 | 
						||
          
 | 
						||
          &.default {
 | 
						||
            background: var(--gray-light);
 | 
						||
            color: var(--text-muted);
 | 
						||
          }
 | 
						||
          
 | 
						||
          &.success {
 | 
						||
            background: var(--success-light);
 | 
						||
            color: var(--success);
 | 
						||
          }
 | 
						||
          
 | 
						||
          &.warning {
 | 
						||
            background: var(--warning-light);
 | 
						||
            color: var(--warning);
 | 
						||
          }
 | 
						||
        }
 | 
						||
        
 | 
						||
        .day-data-info {
 | 
						||
          flex: 1;
 | 
						||
          min-width: 0;
 | 
						||
          
 | 
						||
          .day-data-label {
 | 
						||
            font-size: 22rpx;
 | 
						||
            color: var(--text-secondary);
 | 
						||
            margin-bottom: 6rpx;
 | 
						||
            white-space: nowrap;
 | 
						||
            overflow: hidden;
 | 
						||
            text-overflow: ellipsis;
 | 
						||
          }
 | 
						||
          
 | 
						||
          .day-data-value {
 | 
						||
            font-size: 24rpx;
 | 
						||
            font-weight: 600;
 | 
						||
            
 | 
						||
            &.default {
 | 
						||
              color: var(--text-color);
 | 
						||
            }
 | 
						||
            
 | 
						||
            &.success {
 | 
						||
              color: var(--success);
 | 
						||
            }
 | 
						||
            
 | 
						||
            &.warning {
 | 
						||
              color: var(--warning);
 | 
						||
            }
 | 
						||
          }
 | 
						||
        }
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  .count-list {
 | 
						||
    display: flex;
 | 
						||
    flex-wrap: wrap;
 | 
						||
    margin-top: 16rpx;
 | 
						||
    justify-content: space-between;
 | 
						||
    .count-item {
 | 
						||
      display: flex;
 | 
						||
      flex-direction: column;
 | 
						||
      align-items: center;
 | 
						||
      width: 48%;
 | 
						||
      margin-bottom: 16rpx;
 | 
						||
      padding: 24rpx;
 | 
						||
      background: var(--gray-lighter);
 | 
						||
      border-radius: 12rpx;
 | 
						||
      box-sizing: border-box;
 | 
						||
      border: 1rpx solid var(--border-light);
 | 
						||
      .c-title {
 | 
						||
        color: var(--text-secondary);
 | 
						||
        margin-bottom: 8rpx;
 | 
						||
        font-size: 20rpx;
 | 
						||
      }
 | 
						||
      .c-value {
 | 
						||
        color: var(--text-color);
 | 
						||
        font-size: 40rpx;
 | 
						||
        font-weight: 500;
 | 
						||
        margin-bottom: 8rpx;
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
/* 日历样式 */
 | 
						||
.calendar {
 | 
						||
  background: var(--surface);
 | 
						||
  border-radius: 12rpx;
 | 
						||
  padding: 24rpx;
 | 
						||
  margin-top: 16rpx;
 | 
						||
  border: 1rpx solid var(--border);
 | 
						||
  box-shadow: var(--shadow);
 | 
						||
 | 
						||
  .cal-title {
 | 
						||
    text-align: center;
 | 
						||
    font-weight: 600;
 | 
						||
    font-size: 32rpx;
 | 
						||
    color: var(--title-color);
 | 
						||
    margin-bottom: 24rpx;
 | 
						||
  }
 | 
						||
 | 
						||
  .cal-week-head {
 | 
						||
    display: flex;
 | 
						||
    margin-bottom: 16rpx;
 | 
						||
 | 
						||
    text {
 | 
						||
      flex: 1;
 | 
						||
      text-align: center;
 | 
						||
      font-size: 26rpx;
 | 
						||
      color: var(--text-muted);
 | 
						||
      font-weight: 500;
 | 
						||
      padding: 12rpx 0;
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  .cal-body {
 | 
						||
    .cal-row {
 | 
						||
      display: flex;
 | 
						||
      margin-bottom: 8rpx;
 | 
						||
 | 
						||
      .cal-cell {
 | 
						||
        flex: 1;
 | 
						||
        height: 64rpx;
 | 
						||
        line-height: 64rpx;
 | 
						||
        text-align: center;
 | 
						||
        border-radius: 8rpx;
 | 
						||
        margin: 0 4rpx;
 | 
						||
        background: var(--gray-lighter);
 | 
						||
        font-size: 28rpx;
 | 
						||
        color: var(--text-color);
 | 
						||
        transition: all 0.2s ease;
 | 
						||
        position: relative;
 | 
						||
 | 
						||
        &:active {
 | 
						||
          transform: scale(0.95);
 | 
						||
        }
 | 
						||
 | 
						||
        &.selected {
 | 
						||
          background: var(--primary-color);
 | 
						||
          color: var(--white);
 | 
						||
          font-weight: 600;
 | 
						||
          box-shadow: var(--shadow-md);
 | 
						||
        }
 | 
						||
 | 
						||
        &.empty {
 | 
						||
          background: transparent;
 | 
						||
          pointer-events: none;
 | 
						||
        }
 | 
						||
 | 
						||
        &:not(.empty):not(.selected):hover {
 | 
						||
          background: var(--primary-light);
 | 
						||
          color: var(--white);
 | 
						||
        }
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
:deep() {
 | 
						||
  .uni-scroll-view {
 | 
						||
    overflow: hidden !important;
 | 
						||
  }
 | 
						||
}
 | 
						||
</style>
 |