1048 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			1048 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						||
  <view class="workbench">
 | 
						||
    <!-- 移动设备顶部状态栏 -->
 | 
						||
    <view class="top_bar flex w-full" v-if="isMobile">
 | 
						||
      <view class="chat-header">
 | 
						||
        <view class="header-left">
 | 
						||
          <i class="fas fa-bell header-icon" @click="handleNotification"></i>
 | 
						||
        </view>
 | 
						||
        <view class="header-title">工作台</view>
 | 
						||
        <view class="header-right">
 | 
						||
          <i class="fas fa-search header-icon" @click="handleSearch"></i>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
    </view>
 | 
						||
    <!-- 浏览器环境顶部导航栏 -->
 | 
						||
    <view class="unified-header" v-else>
 | 
						||
      <view class="header-content">
 | 
						||
        <view class="header-left">
 | 
						||
          <i class="fas fa-bell header-icon" @click="handleNotification"></i>
 | 
						||
        </view>
 | 
						||
        <view class="header-title">工作台</view>
 | 
						||
        <view class="header-right">
 | 
						||
          <i class="fas fa-search header-icon" @click="handleSearch"></i>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
    </view>
 | 
						||
 | 
						||
    <!-- 页面内容 -->
 | 
						||
    <scroll-view scroll-y class="unified-content">
 | 
						||
      <!-- 欢迎和天气模块 -->
 | 
						||
      <view class="welcome-section">
 | 
						||
        <view class="welcome-header">
 | 
						||
          <view class="welcome-info">
 | 
						||
            <text class="welcome-text"
 | 
						||
              >{{ getGreeting() }},{{ userName }}</text
 | 
						||
            >
 | 
						||
            <text class="welcome-date">{{ currentDate }}</text>
 | 
						||
          </view>
 | 
						||
          <view class="weather-card">
 | 
						||
            <view class="weather-icon">
 | 
						||
              <i class="fas fa-sun weather-icon-fa"></i>
 | 
						||
            </view>
 | 
						||
            <view class="weather-info">
 | 
						||
              <text class="weather-temp">{{ weather.temperature }}°</text>
 | 
						||
              <text class="weather-desc">{{ weather.description }}</text>
 | 
						||
              <text class="weather-location">{{ weather.location }}</text>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
 | 
						||
      <!-- 工作状态卡片 -->
 | 
						||
      <view class="status-card">
 | 
						||
        <view class="status-header">
 | 
						||
          <text class="status-title">今日工作状态</text>
 | 
						||
          <view class="status-indicator" :class="workStatus">
 | 
						||
            <text class="status-text">{{ workStatusText }}</text>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
        <view class="status-content">
 | 
						||
          <view class="status-item">
 | 
						||
            <text class="status-label">上班时间</text>
 | 
						||
            <text class="status-value">{{ workTime }}</text>
 | 
						||
          </view>
 | 
						||
          <view class="status-item">
 | 
						||
            <text class="status-label">工作时长</text>
 | 
						||
            <text class="status-value">{{ workDuration }}</text>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
 | 
						||
      <!-- 数据统计 -->
 | 
						||
      <view class="stats-section">
 | 
						||
        <view class="stats-grid">
 | 
						||
          <view class="stat-card pending" @click="goToApproval">
 | 
						||
            <view class="stat-icon">
 | 
						||
              <i class="fas fa-clipboard-list stat-icon-fa"></i>
 | 
						||
            </view>
 | 
						||
            <view class="stat-content">
 | 
						||
              <text class="stat-number">{{ pendingApproval }}</text>
 | 
						||
              <text class="stat-label">待审批</text>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
          <view class="stat-card tasks" @click="goToTasks">
 | 
						||
            <view class="stat-icon">
 | 
						||
              <i class="fas fa-check-circle stat-icon-fa"></i>
 | 
						||
            </view>
 | 
						||
            <view class="stat-content">
 | 
						||
              <text class="stat-number">{{ completedTasks }}</text>
 | 
						||
              <text class="stat-label">已完成</text>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
          <view class="stat-card money" @click="goToReimbursement">
 | 
						||
            <view class="stat-icon">
 | 
						||
              <i class="fas fa-money-bill-wave stat-icon-fa"></i>
 | 
						||
            </view>
 | 
						||
            <view class="stat-content">
 | 
						||
              <text class="stat-number">¥{{ reimbursementAmount }}</text>
 | 
						||
              <text class="stat-label">本月报销</text>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
          <view class="stat-card attendance" @click="goToAttendance">
 | 
						||
            <view class="stat-icon">
 | 
						||
              <i class="fas fa-clock stat-icon-fa"></i>
 | 
						||
            </view>
 | 
						||
            <view class="stat-content">
 | 
						||
              <text class="stat-number">{{ attendanceRate }}%</text>
 | 
						||
              <text class="stat-label">出勤率</text>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
 | 
						||
      <!-- 快捷功能 -->
 | 
						||
      <view class="functions-section">
 | 
						||
        <view class="section-header">
 | 
						||
          <text class="section-title">快捷功能</text>
 | 
						||
          <text class="more-btn" @click="showAllFunctions">查看全部</text>
 | 
						||
        </view>
 | 
						||
        <view class="functions-grid">
 | 
						||
          <view
 | 
						||
            class="function-card"
 | 
						||
            v-for="(action, index) in quickActions"
 | 
						||
            :key="index"
 | 
						||
            @click="handleQuickAction(action)"
 | 
						||
          >
 | 
						||
            <view
 | 
						||
              class="function-icon"
 | 
						||
              :style="{ background: action.gradient }"
 | 
						||
            >
 | 
						||
              <i :class="action.iconClass" class="function-icon-fa"></i>
 | 
						||
            </view>
 | 
						||
            <text class="function-name">{{ action.label }}</text>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
 | 
						||
      <!-- 最近动态 -->
 | 
						||
      <view class="recent-section">
 | 
						||
        <view class="section-header">
 | 
						||
          <text class="section-title">最近动态</text>
 | 
						||
        </view>
 | 
						||
        <view class="recent-list">
 | 
						||
          <view
 | 
						||
            class="recent-item"
 | 
						||
            v-for="(item, index) in recentActivities"
 | 
						||
            :key="index"
 | 
						||
            @click="handleRecentItem(item)"
 | 
						||
          >
 | 
						||
            <view
 | 
						||
              class="recent-icon"
 | 
						||
              :style="{ background: item.color + '20' }"
 | 
						||
            >
 | 
						||
              <i :class="item.iconClass" class="recent-icon-fa"></i>
 | 
						||
            </view>
 | 
						||
            <view class="recent-content">
 | 
						||
              <text class="recent-title">{{ item.title }}</text>
 | 
						||
              <text class="recent-desc">{{ item.description }}</text>
 | 
						||
              <text class="recent-time">{{ item.time }}</text>
 | 
						||
            </view>
 | 
						||
            <view class="recent-arrow">
 | 
						||
              <i class="fas fa-chevron-right arrow-icon"></i>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
    </scroll-view>
 | 
						||
  </view>
 | 
						||
</template>
 | 
						||
 | 
						||
<script>
 | 
						||
import { ref, reactive, computed } from "vue";
 | 
						||
import { useAuthStore } from "../../src/store/authStore.js";
 | 
						||
 | 
						||
export default {
 | 
						||
  setup() {
 | 
						||
    const authStore = useAuthStore();
 | 
						||
 | 
						||
    // 用户信息 - 从 Pinia store 获取
 | 
						||
    const userInfo = computed(() => {
 | 
						||
      return (
 | 
						||
        authStore.userInfo || {
 | 
						||
          nickname: "未登录",
 | 
						||
          name: "未登录",
 | 
						||
          department: "未知部门",
 | 
						||
          dept: { name: "未知部门" },
 | 
						||
          employeeId: "N/A",
 | 
						||
          avatar: "static\\imgs\\default_avatar.png",
 | 
						||
          attendanceRate: 0,
 | 
						||
          completedTasks: 0,
 | 
						||
          pendingAmount: "0",
 | 
						||
        }
 | 
						||
      );
 | 
						||
    });
 | 
						||
 | 
						||
    // 登录状态
 | 
						||
    const isLogin = computed(() => {
 | 
						||
      return authStore.isAuthenticated;
 | 
						||
    });
 | 
						||
 | 
						||
    // 设备检测
 | 
						||
    const isMobile = computed(() => {
 | 
						||
      return getApp().globalData.isMobile;
 | 
						||
    });
 | 
						||
 | 
						||
    // 用户信息
 | 
						||
    const userName = authStore.userInfo?.nickname || '未登录';
 | 
						||
 | 
						||
    // 获取当前日期,格式:2024年10月15日 星期二
 | 
						||
    function getFormattedDate() {
 | 
						||
      const now = new Date();
 | 
						||
      const year = now.getFullYear();
 | 
						||
      const month = now.getMonth() + 1;
 | 
						||
      const day = now.getDate();
 | 
						||
      const weekDays = [
 | 
						||
        "星期日",
 | 
						||
        "星期一",
 | 
						||
        "星期二",
 | 
						||
        "星期三",
 | 
						||
        "星期四",
 | 
						||
        "星期五",
 | 
						||
        "星期六",
 | 
						||
      ];
 | 
						||
      const weekDay = weekDays[now.getDay()];
 | 
						||
      return `${year}年${month}月${day}日 ${weekDay}`;
 | 
						||
    }
 | 
						||
    const currentDate = ref(getFormattedDate());
 | 
						||
 | 
						||
    // 工作状态
 | 
						||
    const workStatus = ref("working");
 | 
						||
    const workStatusText = ref("工作中");
 | 
						||
    const workTime = ref("09:00");
 | 
						||
    const workDuration = ref("6小时30分");
 | 
						||
 | 
						||
    // 统计数据
 | 
						||
    const unreadCount = ref(3);
 | 
						||
    const pendingApproval = ref(3);
 | 
						||
    const completedTasks = ref(12);
 | 
						||
    const reimbursementAmount = ref("2,580");
 | 
						||
    const attendanceRate = ref(98);
 | 
						||
 | 
						||
    // 天气信息
 | 
						||
    const weather = reactive({
 | 
						||
      temperature: 22,
 | 
						||
      description: "晴朗",
 | 
						||
      location: "北京市",
 | 
						||
      icon: "fas fa-sun",
 | 
						||
    });
 | 
						||
 | 
						||
    // 快捷功能数据
 | 
						||
    const quickActions = reactive([
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-tasks",
 | 
						||
        label: "任务管理",
 | 
						||
        action: "tasks",
 | 
						||
        gradient: "linear-gradient(135deg, #3498db, #5dade2)",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-calendar-alt",
 | 
						||
        label: "请假申请",
 | 
						||
        action: "leave",
 | 
						||
        gradient: "linear-gradient(135deg, #ef4444, #f87171)",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-receipt",
 | 
						||
        label: "报销提交",
 | 
						||
        action: "reimbursement",
 | 
						||
        gradient: "linear-gradient(135deg, #10b981, #34d399)",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-clock",
 | 
						||
        label: "考勤打卡",
 | 
						||
        action: "checkin",
 | 
						||
        gradient: "linear-gradient(135deg, #3b82f6, #60a5fa)",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-building",
 | 
						||
        label: "会议预订",
 | 
						||
        action: "meeting",
 | 
						||
        gradient: "linear-gradient(135deg, #8b5cf6, #a78bfa)",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-users",
 | 
						||
        label: "客户管理",
 | 
						||
        action: "customer",
 | 
						||
        gradient: "linear-gradient(135deg, #f59e0b, #fbbf24)",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-chart-bar",
 | 
						||
        label: "工作报告",
 | 
						||
        action: "report",
 | 
						||
        gradient: "linear-gradient(135deg, #06b6d4, #22d3ee)",
 | 
						||
      },
 | 
						||
    ]);
 | 
						||
 | 
						||
    // 最近动态数据
 | 
						||
    const recentActivities = reactive([
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-check-circle",
 | 
						||
        title: "请假申请已通过",
 | 
						||
        description: "您的年假申请已获得部门经理批准",
 | 
						||
        time: "2小时前",
 | 
						||
        color: "#10b981",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-money-bill-wave",
 | 
						||
        title: "报销到账通知",
 | 
						||
        description: "差旅费报销 ¥1,200 已到账",
 | 
						||
        time: "昨天",
 | 
						||
        color: "#3b82f6",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-calendar-check",
 | 
						||
        title: "会议提醒",
 | 
						||
        description: "项目评审会议将在30分钟后开始",
 | 
						||
        time: "3小时前",
 | 
						||
        color: "#f59e0b",
 | 
						||
      },
 | 
						||
      {
 | 
						||
        iconClass: "fas fa-exclamation-triangle",
 | 
						||
        title: "考勤异常",
 | 
						||
        description: "今日下班打卡时间异常,请确认",
 | 
						||
        time: "昨天",
 | 
						||
        color: "#ef4444",
 | 
						||
      },
 | 
						||
    ]);
 | 
						||
 | 
						||
    // 方法
 | 
						||
    const handleSearch = () => {
 | 
						||
      uni.showToast({
 | 
						||
        title: "搜索功能",
 | 
						||
        icon: "none",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    const handleNotification = () => {
 | 
						||
      uni.switchTab({
 | 
						||
        url: "/pages/message/message",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    const goToApproval = () => {
 | 
						||
      uni.showToast({
 | 
						||
        title: "跳转审批列表",
 | 
						||
        icon: "none",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    const goToTasks = () => {
 | 
						||
      uni.showToast({
 | 
						||
        title: "跳转任务列表",
 | 
						||
        icon: "none",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    const goToAttendance = () => {
 | 
						||
      uni.showToast({
 | 
						||
        title: "跳转考勤详情",
 | 
						||
        icon: "none",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    const goToReimbursement = () => {
 | 
						||
      uni.showToast({
 | 
						||
        title: "跳转报销进度",
 | 
						||
        icon: "none",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    const showAllFunctions = () => {
 | 
						||
      uni.switchTab({
 | 
						||
        url: "/pages/function/function",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    const handleQuickAction = (action) => {
 | 
						||
      switch (action.action) {
 | 
						||
        case "tasks":
 | 
						||
          uni.navigateTo({
 | 
						||
            url: "/pages/tasks/index",
 | 
						||
          });
 | 
						||
          break;
 | 
						||
        case "leave":
 | 
						||
          uni.showToast({
 | 
						||
            title: "请假申请功能开发中",
 | 
						||
            icon: "none",
 | 
						||
          });
 | 
						||
          break;
 | 
						||
        case "reimbursement":
 | 
						||
          uni.showToast({
 | 
						||
            title: "报销提交功能开发中",
 | 
						||
            icon: "none",
 | 
						||
          });
 | 
						||
          break;
 | 
						||
        case "checkin":
 | 
						||
          uni.showToast({
 | 
						||
            title: "考勤打卡功能开发中",
 | 
						||
            icon: "none",
 | 
						||
          });
 | 
						||
          break;
 | 
						||
        case "meeting":
 | 
						||
          uni.showToast({
 | 
						||
            title: "会议预订功能开发中",
 | 
						||
            icon: "none",
 | 
						||
          });
 | 
						||
          break;
 | 
						||
        case "customer":
 | 
						||
          uni.showToast({
 | 
						||
            title: "客户管理功能开发中",
 | 
						||
            icon: "none",
 | 
						||
          });
 | 
						||
          break;
 | 
						||
        case "report":
 | 
						||
          uni.showToast({
 | 
						||
            title: "工作报告功能开发中",
 | 
						||
            icon: "none",
 | 
						||
          });
 | 
						||
          break;
 | 
						||
        default:
 | 
						||
          uni.showToast({
 | 
						||
            title: `打开${action.label}`,
 | 
						||
            icon: "none",
 | 
						||
          });
 | 
						||
      }
 | 
						||
    };
 | 
						||
 | 
						||
    const handleRecentItem = (item) => {
 | 
						||
      uni.showToast({
 | 
						||
        title: `查看${item.title}`,
 | 
						||
        icon: "none",
 | 
						||
      });
 | 
						||
    };
 | 
						||
 | 
						||
    // 获取天气信息
 | 
						||
    const getWeatherInfo = () => {
 | 
						||
      // 这里可以调用天气API获取实时天气
 | 
						||
      // 目前使用模拟数据
 | 
						||
      const weatherData = {
 | 
						||
        temperature: Math.floor(Math.random() * 15) + 15, // 15-30度随机温度
 | 
						||
        description: ["晴朗", "多云", "小雨", "阴天"][
 | 
						||
          Math.floor(Math.random() * 4)
 | 
						||
        ],
 | 
						||
        location: "北京市",
 | 
						||
        icon: "fas fa-sun",
 | 
						||
      };
 | 
						||
 | 
						||
      weather.temperature = weatherData.temperature;
 | 
						||
      weather.description = weatherData.description;
 | 
						||
      weather.location = weatherData.location;
 | 
						||
      weather.icon = weatherData.icon;
 | 
						||
    };
 | 
						||
 | 
						||
    // 获取问候语
 | 
						||
    const getGreeting = () => {
 | 
						||
      const hour = new Date().getHours();
 | 
						||
      if (hour < 6) return "夜深了";
 | 
						||
      if (hour < 9) return "早上好";
 | 
						||
      if (hour < 12) return "上午好";
 | 
						||
      if (hour < 14) return "中午好";
 | 
						||
      if (hour < 18) return "下午好";
 | 
						||
      if (hour < 22) return "晚上好";
 | 
						||
      return "夜深了";
 | 
						||
    };
 | 
						||
 | 
						||
    return {
 | 
						||
      userName,
 | 
						||
      currentDate,
 | 
						||
      workStatus,
 | 
						||
      workStatusText,
 | 
						||
      workTime,
 | 
						||
      workDuration,
 | 
						||
      unreadCount,
 | 
						||
      pendingApproval,
 | 
						||
      completedTasks,
 | 
						||
      reimbursementAmount,
 | 
						||
      attendanceRate,
 | 
						||
      weather,
 | 
						||
      quickActions,
 | 
						||
      recentActivities,
 | 
						||
      handleSearch,
 | 
						||
      handleNotification,
 | 
						||
      goToApproval,
 | 
						||
      goToTasks,
 | 
						||
      goToAttendance,
 | 
						||
      goToReimbursement,
 | 
						||
      showAllFunctions,
 | 
						||
      handleQuickAction,
 | 
						||
      handleRecentItem,
 | 
						||
      getWeatherInfo,
 | 
						||
      getGreeting,
 | 
						||
      isMobile,
 | 
						||
    };
 | 
						||
  },
 | 
						||
};
 | 
						||
</script>
 | 
						||
 | 
						||
<style lang="scss" scoped>
 | 
						||
.workbench {
 | 
						||
  min-height: 100vh;
 | 
						||
  background: var(--gradient-surface);
 | 
						||
  position: relative;
 | 
						||
  width: 100vw;
 | 
						||
  box-sizing: border-box;
 | 
						||
}
 | 
						||
 | 
						||
/* 浏览器环境下的顶部间距 */
 | 
						||
.unified-header + .unified-content {
 | 
						||
  margin-top: calc(var(--status-bar-height) + 88rpx);
 | 
						||
  padding-top: 30rpx;
 | 
						||
}
 | 
						||
 | 
						||
/* 支持安全区域的设备 - 移动设备不需要额外的 padding-top,因为使用了 top_bar */
 | 
						||
 | 
						||
/* 移动设备顶部状态栏 */
 | 
						||
.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 + .unified-content {
 | 
						||
    margin-top: calc(var(--status-bar-height) + 88rpx + env(safe-area-inset-top));
 | 
						||
    padding-top: 30rpx;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
/* 移动设备下的导航栏样式 */
 | 
						||
.top_bar .chat-header {
 | 
						||
  background: transparent;
 | 
						||
  border-bottom: none;
 | 
						||
  box-shadow: none;
 | 
						||
  width: 100%;
 | 
						||
  height: 88rpx;
 | 
						||
  padding: 0 20rpx;
 | 
						||
  box-sizing: border-box;
 | 
						||
  display: flex;
 | 
						||
  justify-content: space-between;
 | 
						||
  align-items: center;
 | 
						||
}
 | 
						||
 | 
						||
.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;
 | 
						||
}
 | 
						||
 | 
						||
/* 移动设备下为内容添加顶部间距 */
 | 
						||
.top_bar + .unified-content {
 | 
						||
  margin-top: calc(var(--status-bar-height) + 88rpx);
 | 
						||
  padding-top: 30rpx;
 | 
						||
}
 | 
						||
 | 
						||
/* 浏览器环境顶部导航栏 */
 | 
						||
.unified-header {
 | 
						||
  background: var(--gradient-primary);
 | 
						||
  box-shadow: var(--shadow-lg);
 | 
						||
  position: fixed;
 | 
						||
  top: 0;
 | 
						||
  left: 0;
 | 
						||
  right: 0;
 | 
						||
  z-index: 9999;
 | 
						||
  height: calc(var(--status-bar-height) + 88rpx);
 | 
						||
}
 | 
						||
 | 
						||
.unified-header .header-content {
 | 
						||
  padding: 20rpx 30rpx;
 | 
						||
  padding-top: calc(var(--status-bar-height) + 20rpx);
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  justify-content: space-between;
 | 
						||
  height: 100%;
 | 
						||
  box-sizing: border-box;
 | 
						||
}
 | 
						||
 | 
						||
.unified-header .header-title {
 | 
						||
  flex: 1;
 | 
						||
  text-align: center;
 | 
						||
  color: var(--white);
 | 
						||
  font-size: 32rpx;
 | 
						||
  font-weight: 600;
 | 
						||
  margin: 0 20rpx;
 | 
						||
}
 | 
						||
 | 
						||
.unified-header .header-left,
 | 
						||
.unified-header .header-right {
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  min-width: 80rpx;
 | 
						||
}
 | 
						||
 | 
						||
.unified-header .header-right {
 | 
						||
  justify-content: flex-end;
 | 
						||
}
 | 
						||
 | 
						||
.unified-header .header-icon {
 | 
						||
  color: var(--white);
 | 
						||
  font-size: 36rpx;
 | 
						||
  padding: 10rpx;
 | 
						||
  transition: all 0.3s ease;
 | 
						||
}
 | 
						||
 | 
						||
.unified-header .header-icon:active {
 | 
						||
  background: rgba(255, 255, 255, 0.2);
 | 
						||
  transform: scale(0.95);
 | 
						||
}
 | 
						||
 | 
						||
/* 支持安全区域的设备 */
 | 
						||
@supports (padding: max(0px)) {
 | 
						||
  .unified-header {
 | 
						||
    height: calc(var(--status-bar-height) + 88rpx + env(safe-area-inset-top));
 | 
						||
  }
 | 
						||
  
 | 
						||
  .unified-header .header-content {
 | 
						||
    padding-top: calc(var(--status-bar-height) + 20rpx + env(safe-area-inset-top));
 | 
						||
  }
 | 
						||
  
 | 
						||
  .unified-header + .unified-content {
 | 
						||
    margin-top: calc(var(--status-bar-height) + 88rpx + env(safe-area-inset-top));
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/* 欢迎和天气模块 */
 | 
						||
.welcome-section {
 | 
						||
  margin-bottom: 30rpx;
 | 
						||
}
 | 
						||
 | 
						||
.welcome-header {
 | 
						||
  display: flex;
 | 
						||
  justify-content: space-between;
 | 
						||
  align-items: flex-start;
 | 
						||
  background: var(--gradient-primary);
 | 
						||
  border-radius: 20rpx;
 | 
						||
  padding: 40rpx 32rpx;
 | 
						||
  color: var(--white);
 | 
						||
  box-shadow: var(--shadow-lg);
 | 
						||
}
 | 
						||
 | 
						||
.welcome-info {
 | 
						||
  flex: 1;
 | 
						||
}
 | 
						||
 | 
						||
.welcome-text {
 | 
						||
  font-size: 36rpx;
 | 
						||
  font-weight: 600;
 | 
						||
  margin-bottom: 12rpx;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.welcome-date {
 | 
						||
  font-size: 26rpx;
 | 
						||
  opacity: 0.9;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.weather-card {
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  background: rgba(255, 255, 255, 0.15);
 | 
						||
  border-radius: 16rpx;
 | 
						||
  padding: 20rpx 24rpx;
 | 
						||
  backdrop-filter: blur(10rpx);
 | 
						||
  border: 1rpx solid rgba(255, 255, 255, 0.2);
 | 
						||
}
 | 
						||
 | 
						||
.weather-icon {
 | 
						||
  width: 60rpx;
 | 
						||
  height: 60rpx;
 | 
						||
  border-radius: 12rpx;
 | 
						||
  background: rgba(255, 255, 255, 0.2);
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  justify-content: center;
 | 
						||
  margin-right: 16rpx;
 | 
						||
}
 | 
						||
 | 
						||
.weather-icon-fa {
 | 
						||
  font-size: 28rpx;
 | 
						||
  color: var(--white);
 | 
						||
}
 | 
						||
 | 
						||
.weather-info {
 | 
						||
  display: flex;
 | 
						||
  flex-direction: column;
 | 
						||
  align-items: flex-end;
 | 
						||
}
 | 
						||
 | 
						||
.weather-temp {
 | 
						||
  font-size: 32rpx;
 | 
						||
  font-weight: 700;
 | 
						||
  margin-bottom: 4rpx;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.weather-desc {
 | 
						||
  font-size: 22rpx;
 | 
						||
  opacity: 0.9;
 | 
						||
  margin-bottom: 4rpx;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.weather-location {
 | 
						||
  font-size: 20rpx;
 | 
						||
  opacity: 0.8;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
/* 工作状态卡片 */
 | 
						||
.status-card {
 | 
						||
  background: var(--white);
 | 
						||
  border-radius: 16rpx;
 | 
						||
  padding: 32rpx;
 | 
						||
  margin-bottom: 24rpx;
 | 
						||
  box-shadow: var(--shadow);
 | 
						||
  border: 1rpx solid var(--border-light);
 | 
						||
}
 | 
						||
 | 
						||
.status-header {
 | 
						||
  display: flex;
 | 
						||
  justify-content: space-between;
 | 
						||
  align-items: center;
 | 
						||
  margin-bottom: 30rpx;
 | 
						||
}
 | 
						||
 | 
						||
.status-title {
 | 
						||
  font-size: 32rpx;
 | 
						||
  font-weight: 600;
 | 
						||
  color: var(--text-color);
 | 
						||
}
 | 
						||
 | 
						||
.status-indicator {
 | 
						||
  padding: 12rpx 24rpx;
 | 
						||
  border-radius: 20rpx;
 | 
						||
  font-size: 24rpx;
 | 
						||
}
 | 
						||
 | 
						||
.status-indicator.working {
 | 
						||
  background: var(--gradient-success);
 | 
						||
  color: var(--white);
 | 
						||
}
 | 
						||
 | 
						||
.status-text {
 | 
						||
  font-weight: 500;
 | 
						||
}
 | 
						||
 | 
						||
.status-content {
 | 
						||
  display: flex;
 | 
						||
  gap: 60rpx;
 | 
						||
}
 | 
						||
 | 
						||
.status-item {
 | 
						||
  flex: 1;
 | 
						||
}
 | 
						||
 | 
						||
.status-label {
 | 
						||
  font-size: 24rpx;
 | 
						||
  color: var(--text-secondary);
 | 
						||
  margin-bottom: 8rpx;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.status-value {
 | 
						||
  font-size: 32rpx;
 | 
						||
  font-weight: 600;
 | 
						||
  color: var(--text-color);
 | 
						||
}
 | 
						||
 | 
						||
/* 数据统计 */
 | 
						||
.stats-section {
 | 
						||
  margin-bottom: 30rpx;
 | 
						||
}
 | 
						||
 | 
						||
.stats-grid {
 | 
						||
  display: grid;
 | 
						||
  grid-template-columns: 1fr 1fr;
 | 
						||
  gap: 20rpx;
 | 
						||
  width: 100%;
 | 
						||
  box-sizing: border-box;
 | 
						||
}
 | 
						||
 | 
						||
.stat-card {
 | 
						||
  background: var(--white);
 | 
						||
  border-radius: 12rpx;
 | 
						||
  padding: 24rpx;
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  box-shadow: var(--shadow);
 | 
						||
  border: 1rpx solid var(--border-light);
 | 
						||
  transition: all 0.3s ease;
 | 
						||
  width: 100%;
 | 
						||
  box-sizing: border-box;
 | 
						||
  overflow: hidden;
 | 
						||
}
 | 
						||
 | 
						||
.stat-card:active {
 | 
						||
  transform: scale(0.98);
 | 
						||
}
 | 
						||
 | 
						||
.stat-icon {
 | 
						||
  width: 80rpx;
 | 
						||
  height: 80rpx;
 | 
						||
  border-radius: 16rpx;
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  justify-content: center;
 | 
						||
  margin-right: 20rpx;
 | 
						||
}
 | 
						||
 | 
						||
.stat-card.pending .stat-icon {
 | 
						||
  background: var(--gradient-error);
 | 
						||
}
 | 
						||
 | 
						||
.stat-card.tasks .stat-icon {
 | 
						||
  background: var(--gradient-success);
 | 
						||
}
 | 
						||
 | 
						||
.stat-card.money .stat-icon {
 | 
						||
  background: var(--gradient-primary);
 | 
						||
}
 | 
						||
 | 
						||
.stat-card.attendance .stat-icon {
 | 
						||
  background: var(--gradient-warning);
 | 
						||
}
 | 
						||
 | 
						||
.stat-content {
 | 
						||
  flex: 1;
 | 
						||
}
 | 
						||
 | 
						||
.stat-number {
 | 
						||
  font-size: 36rpx;
 | 
						||
  font-weight: 700;
 | 
						||
  color: var(--text-color);
 | 
						||
  margin-bottom: 8rpx;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.stat-label {
 | 
						||
  font-size: 24rpx;
 | 
						||
  color: var(--text-secondary);
 | 
						||
}
 | 
						||
 | 
						||
/* 快捷功能 */
 | 
						||
.functions-section {
 | 
						||
  margin-bottom: 30rpx;
 | 
						||
}
 | 
						||
 | 
						||
.section-header {
 | 
						||
  display: flex;
 | 
						||
  justify-content: space-between;
 | 
						||
  align-items: center;
 | 
						||
  margin-bottom: 20rpx;
 | 
						||
}
 | 
						||
 | 
						||
.section-title {
 | 
						||
  font-size: 32rpx;
 | 
						||
  font-weight: 600;
 | 
						||
  color: var(--text-color);
 | 
						||
}
 | 
						||
 | 
						||
.more-btn {
 | 
						||
  font-size: 26rpx;
 | 
						||
  color: var(--primary-color);
 | 
						||
}
 | 
						||
 | 
						||
.functions-grid {
 | 
						||
  display: grid;
 | 
						||
  grid-template-columns: repeat(3, 1fr);
 | 
						||
  gap: 20rpx;
 | 
						||
  width: 100%;
 | 
						||
  box-sizing: border-box;
 | 
						||
}
 | 
						||
 | 
						||
.function-card {
 | 
						||
  background: var(--white);
 | 
						||
  border-radius: 12rpx;
 | 
						||
  padding: 24rpx 16rpx;
 | 
						||
  display: flex;
 | 
						||
  flex-direction: column;
 | 
						||
  align-items: center;
 | 
						||
  box-shadow: var(--shadow);
 | 
						||
  border: 1rpx solid var(--border-light);
 | 
						||
  transition: all 0.3s ease;
 | 
						||
  width: 100%;
 | 
						||
  box-sizing: border-box;
 | 
						||
  overflow: hidden;
 | 
						||
}
 | 
						||
 | 
						||
.function-card:active {
 | 
						||
  transform: scale(0.95);
 | 
						||
}
 | 
						||
 | 
						||
.function-icon {
 | 
						||
  width: 80rpx;
 | 
						||
  height: 80rpx;
 | 
						||
  border-radius: 20rpx;
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  justify-content: center;
 | 
						||
  margin-bottom: 20rpx;
 | 
						||
}
 | 
						||
 | 
						||
.function-name {
 | 
						||
  font-size: 24rpx;
 | 
						||
  color: var(--text-color);
 | 
						||
  text-align: center;
 | 
						||
  font-weight: 500;
 | 
						||
}
 | 
						||
 | 
						||
/* 最近动态 */
 | 
						||
.recent-section {
 | 
						||
  margin-bottom: 0;
 | 
						||
}
 | 
						||
 | 
						||
.recent-list {
 | 
						||
  background: var(--white);
 | 
						||
  border-radius: 12rpx;
 | 
						||
  overflow: hidden;
 | 
						||
  box-shadow: var(--shadow);
 | 
						||
  border: 1rpx solid var(--border-light);
 | 
						||
}
 | 
						||
 | 
						||
.recent-item {
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  padding: 30rpx;
 | 
						||
  border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
 | 
						||
  transition: background-color 0.3s ease;
 | 
						||
}
 | 
						||
 | 
						||
.recent-item:last-child {
 | 
						||
  border-bottom: none;
 | 
						||
}
 | 
						||
 | 
						||
.recent-item:active {
 | 
						||
  background-color: rgba(0, 0, 0, 0.02);
 | 
						||
}
 | 
						||
 | 
						||
.recent-icon {
 | 
						||
  width: 60rpx;
 | 
						||
  height: 60rpx;
 | 
						||
  border-radius: 12rpx;
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  justify-content: center;
 | 
						||
  margin-right: 20rpx;
 | 
						||
}
 | 
						||
 | 
						||
.recent-content {
 | 
						||
  flex: 1;
 | 
						||
}
 | 
						||
 | 
						||
.recent-title {
 | 
						||
  font-size: 28rpx;
 | 
						||
  font-weight: 600;
 | 
						||
  color: var(--text-color);
 | 
						||
  margin-bottom: 8rpx;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.recent-desc {
 | 
						||
  font-size: 24rpx;
 | 
						||
  color: var(--text-secondary);
 | 
						||
  margin-bottom: 8rpx;
 | 
						||
  display: block;
 | 
						||
}
 | 
						||
 | 
						||
.recent-time {
 | 
						||
  font-size: 22rpx;
 | 
						||
  color: var(--text-muted);
 | 
						||
}
 | 
						||
 | 
						||
.recent-arrow {
 | 
						||
  margin-left: 20rpx;
 | 
						||
}
 | 
						||
 | 
						||
/* 底部安全区域适配 */
 | 
						||
.safe-area-bottom {
 | 
						||
  padding-bottom: constant(safe-area-inset-bottom);
 | 
						||
  padding-bottom: env(safe-area-inset-bottom);
 | 
						||
}
 | 
						||
 | 
						||
/* 响应式设计 */
 | 
						||
@media screen and (max-width: 750rpx) {
 | 
						||
  .page-content {
 | 
						||
    padding: 20rpx;
 | 
						||
    padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
 | 
						||
    min-height: calc(100vh - 120rpx);
 | 
						||
  }
 | 
						||
 | 
						||
  .welcome-header {
 | 
						||
    flex-direction: column;
 | 
						||
    align-items: flex-start;
 | 
						||
    gap: 20rpx;
 | 
						||
  }
 | 
						||
 | 
						||
  .weather-card {
 | 
						||
    align-self: flex-end;
 | 
						||
  }
 | 
						||
 | 
						||
  .stats-grid {
 | 
						||
    gap: 15rpx;
 | 
						||
  }
 | 
						||
 | 
						||
  .functions-grid {
 | 
						||
    grid-template-columns: repeat(2, 1fr);
 | 
						||
    gap: 15rpx;
 | 
						||
  }
 | 
						||
}
 | 
						||
</style>
 |