babyhealth/pages/index/index.vue
2026-02-06 20:21:10 +08:00

1427 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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-tasks"></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="action.id"
@click="handleQuickAction(action, index)"
>
<view class="function-icon">
<i :class="action.iconClass" class="function-icon-fa"></i>
</view>
<text class="function-name">{{ action.label }}</text>
</view>
<!-- 第九个加号按钮 -->
<view class="function-card add-card" @click="openSortModal">
<view class="add-icon">
<i class="fas fa-plus add-icon-fa"></i>
</view>
<!-- <text class="add-text">调整排序</text> -->
</view>
</view>
</view>
<!-- 排序调整弹窗 -->
<view class="sort-modal" v-if="showSortModal" @click="closeSortModal">
<view class="sort-content" @click.stop>
<view class="sort-header">
<text class="sort-title">调整快捷功能排序</text>
<view class="close-btn" @click="closeSortModal">
<i class="fas fa-times"></i>
</view>
</view>
<view class="sort-grid">
<view
class="sort-item"
v-for="(action, index) in sortableActions"
:key="action.id"
@touchstart="onTouchStart($event, index)"
@touchmove="onTouchMove($event, index)"
@touchend="onTouchEnd($event, index)"
>
<view class="sort-item-content">
<view class="sort-item-icon">
<i :class="action.iconClass" class="sort-icon-fa"></i>
</view>
<text class="sort-item-name">{{ action.label }}</text>
<view class="sort-handle">
<i class="fas fa-grip-vertical"></i>
</view>
</view>
</view>
</view>
<view class="sort-footer">
<button class="sort-btn cancel" @click="closeSortModal">
取消
</button>
<button class="sort-btn confirm" @click="saveSortOrder">
保存
</button>
</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([
{
id: 1,
iconClass: "fas fa-route",
label: "考勤打卡",
action: "attendance",
},
{
id: 2,
iconClass: "fas fa-chart-bar",
label: "业务数据",
action: "businessData",
},
{
id: 3,
iconClass: "fas fa-tasks",
label: "任务管理",
action: "tasks",
},
{
id: 4,
iconClass: "fas fa-calendar-alt",
label: "请假申请",
action: "leave",
},
{
id: 5,
iconClass: "fas fa-receipt",
label: "报销提交",
action: "reimbursement",
},
{
id: 6,
iconClass: "fas fa-clock",
label: "考勤打卡",
action: "checkin",
},
{
id: 7,
iconClass: "fas fa-building",
label: "会议预订",
action: "meeting",
},
{
id: 8,
iconClass: "fas fa-users",
label: "客户管理",
action: "customer",
},
]);
// 排序弹窗相关
const showSortModal = ref(false);
const sortableActions = ref([]);
const dragIndex = ref(-1);
const dragStartY = ref(0);
const dragOffset = ref(0);
// 最近动态数据
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.navigateTo({
url: "/pages/tasks/approval?activeTab=pending"
});
};
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, index) => {
switch (action.action) {
//跳转任务页面
case "tasks":
uni.navigateTo({
url: "/pages/tasks/index",
});
break;
//跳转考勤页面
case "attendance":
uni.navigateTo({
url: "/pages/hr/attendance/index",
});
break;
//跳转业务数据页面
case "businessData":
uni.navigateTo({
url: "/pages/businessDatas/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;
//跳转其他页面
default:
uni.showToast({
title: `打开${action.label}`,
icon: "none",
});
}
};
// 排序相关方法
const openSortModal = () => {
sortableActions.value = [...quickActions];
showSortModal.value = true;
};
const closeSortModal = () => {
showSortModal.value = false;
sortableActions.value = [];
};
const saveSortOrder = () => {
// 更新原始数据
quickActions.splice(0, quickActions.length, ...sortableActions.value);
closeSortModal();
uni.showToast({
title: "排序已保存",
icon: "success",
});
};
// 拖拽排序相关方法
const onTouchStart = (e, index) => {
dragIndex.value = index;
dragStartY.value = e.touches[0].clientY;
dragOffset.value = 0;
};
const onTouchMove = (e, index) => {
if (dragIndex.value === -1) return;
const currentY = e.touches[0].clientY;
dragOffset.value = currentY - dragStartY.value;
};
const onTouchEnd = (e, index) => {
if (dragIndex.value === -1) return;
const itemHeight = 80; // 每个项目的高度
const moveDistance = Math.round(dragOffset.value / itemHeight);
if (moveDistance !== 0) {
const newIndex = Math.max(
0,
Math.min(sortableActions.value.length - 1, index + moveDistance)
);
if (newIndex !== index) {
// 交换位置
const item = sortableActions.value.splice(index, 1)[0];
sortableActions.value.splice(newIndex, 0, item);
}
}
dragIndex.value = -1;
dragOffset.value = 0;
};
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,
showSortModal,
sortableActions,
recentActivities,
handleSearch,
handleNotification,
goToApproval,
goToTasks,
goToAttendance,
goToReimbursement,
showAllFunctions,
handleQuickAction,
openSortModal,
closeSortModal,
saveSortOrder,
onTouchStart,
onTouchMove,
onTouchEnd,
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;
i {
font-size: 40rpx;
color: var(--primary-color);
}
}
// .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);
grid-template-rows: repeat(3, 1fr);
gap: 20rpx;
width: 100%;
box-sizing: border-box;
height: 600rpx; /* 固定高度,确保九宫格 */
}
.function-card {
background: var(--white);
border-radius: 12rpx;
padding: 24rpx 16rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: 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;
i {
font-size: 40rpx;
color: var(--primary-color);
}
}
.function-name {
font-size: 24rpx;
color: var(--text-color);
text-align: center;
font-weight: 500;
}
/* 第九个加号按钮特殊样式 */
.add-card {
border: 2rpx dashed var(--border-color);
position: relative;
overflow: hidden;
}
.add-card:active {
transform: scale(0.95);
background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
}
.add-icon {
width: 120rpx;
height: 120rpx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
i {
font-size: 100rpx;
color: var(--primary-color);
}
}
.add-icon::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60rpx;
height: 60rpx;
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
50% {
transform: translate(-50%, -50%) scale(1.2);
opacity: 0.7;
}
100% {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
}
.add-icon-fa {
font-size: 32rpx;
color: var(--white);
position: relative;
z-index: 1;
font-weight: 300;
}
.add-text {
font-size: 22rpx;
color: var(--text-secondary);
text-align: center;
font-weight: 500;
letter-spacing: 0.5rpx;
}
/* 排序弹窗 */
.sort-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
box-sizing: border-box;
}
.sort-content {
background: var(--white);
border-radius: 20rpx;
width: 100%;
max-width: 600rpx;
max-height: 80vh;
overflow: hidden;
box-shadow: var(--shadow-xl);
}
.sort-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 40rpx 30rpx 20rpx;
border-bottom: 1rpx solid var(--border-light);
}
.sort-title {
font-size: 32rpx;
font-weight: 600;
color: var(--text-color);
}
.close-btn {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: var(--bg-light);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.close-btn:active {
background: var(--border-light);
transform: scale(0.95);
}
.close-btn i {
font-size: 24rpx;
color: var(--text-secondary);
}
.sort-grid {
max-height: 60vh;
overflow-y: auto;
padding: 20rpx 0;
}
.sort-item {
padding: 0 30rpx;
margin-bottom: 10rpx;
}
.sort-item-content {
display: flex;
align-items: center;
padding: 20rpx;
background: var(--bg-light);
border-radius: 12rpx;
transition: all 0.3s ease;
}
.sort-item-content:active {
background: var(--border-light);
}
.sort-item-icon {
width: 60rpx;
height: 60rpx;
border-radius: 12rpx;
background: var(--primary-color);
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
}
.sort-icon-fa {
font-size: 28rpx;
color: var(--white);
}
.sort-item-name {
flex: 1;
font-size: 28rpx;
color: var(--text-color);
font-weight: 500;
}
.sort-handle {
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
}
.sort-handle i {
font-size: 20rpx;
color: var(--text-muted);
}
.sort-footer {
display: flex;
gap: 20rpx;
padding: 30rpx;
border-top: 1rpx solid var(--border-light);
}
.sort-btn {
flex: 1;
height: 80rpx;
border-radius: 12rpx;
font-size: 28rpx;
font-weight: 500;
border: none;
transition: all 0.3s ease;
}
.sort-btn.cancel {
background: var(--bg-light);
color: var(--text-secondary);
}
.sort-btn.cancel:active {
background: var(--border-light);
}
.sort-btn.confirm {
background: var(--gradient-primary);
color: var(--white);
}
.sort-btn.confirm:active {
transform: scale(0.98);
}
/* 最近动态 */
.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(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 15rpx;
height: 500rpx; /* 小屏幕下调整高度 */
}
}
</style>