zhxy-jzd/src/pages/base/home/index.vue
2025-05-30 17:22:30 +08:00

809 lines
19 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="home-page">
<view class="content-container">
<!-- 用户信息卡片 -->
<view class="user-info-card">
<view class="user-content">
<view class="user-avatar">
<image :src="currentStudent.avatar || '/static/base/home/11222.png'" class="avatar-img"></image>
<view class="avatar-ring"></view>
</view>
<view class="user-details">
<text class="user-name">{{ currentStudent.name }}</text>
<view class="user-class-container">
<view class="class-tag">
<text class="user-class">{{ currentStudent.grade }} {{ currentStudent.class }}</text>
</view>
</view>
</view>
<view class="switch-btn" @click="showStudentSelector">
<u-icon name="arrow-down" size="12" color="#fff"></u-icon>
<text>切换</text>
</view>
</view>
</view>
<!-- 学校横幅 -->
<view class="school-banner">
<view class="banner-content">
<image src="/static/base/home/2211.png" class="banner-img"></image>
<view class="banner-overlay">
<view class="banner-text">
<text class="banner-title">智慧校园</text>
<text class="banner-subtitle">让教育更智能让成长更精彩</text>
</view>
</view>
</view>
</view>
<!-- 功能菜单 -->
<view class="menu-section">
<view class="section-title">
<text class="title-text">校园服务</text>
<view class="title-line"></view>
</view>
<view class="grid-menu">
<view
v-for="(item, index) in menuItems"
:key="index"
class="grid-item"
@click="handleMenuClick(item)"
>
<view class="grid-icon-container">
<view class="icon-background"></view>
<image :src="item.icon" class="grid-icon"></image>
</view>
<text class="grid-text">{{ item.title }}</text>
</view>
</view>
</view>
<!-- 通知公告 -->
<view class="notice-section">
<view class="section-title">
<text class="title-text">通知公告</text>
<view class="title-line"></view>
</view>
<view class="notice-list">
<view
v-for="(notice, index) in announcements"
:key="index"
class="notice-item"
@click="navigateTo('/pages/base/home/detail')"
>
<view class="notice-icon">
<u-icon name="bell" size="20" color="#4A90E2"></u-icon>
</view>
<view class="notice-content">
<text class="notice-title">{{ notice.title }}</text>
<text class="notice-desc">{{ notice.description }}</text>
<view class="notice-footer">
<text class="notice-date">{{ notice.date }}</text>
<view class="notice-arrow">
<u-icon name="arrow-right" size="12" color="#C8C9CC"></u-icon>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 学生选择弹窗 -->
<u-popup
:show="showSelector"
@close="showSelector = false"
mode="bottom"
round="20"
>
<view class="student-selector">
<view class="selector-header">
<text class="selector-title">选择学生</text>
<view class="close-btn" @click="showSelector = false">
<u-icon name="close" size="18" color="#909399"></u-icon>
</view>
</view>
<view class="student-list">
<view
v-for="(student, index) in studentList"
:key="index"
class="student-item"
:class="{ 'student-item-active': currentStudent.id === student.id }"
@click="switchStudent(student)"
>
<view class="student-avatar">
<image :src="student.avatar || '/static/base/home/11222.png'" class="avatar-img"></image>
</view>
<view class="student-info">
<text class="student-name">{{ student.name }}</text>
<text class="student-class">{{ student.grade }} {{ student.class }}</text>
</view>
<view class="check-icon" v-if="currentStudent.id === student.id">
<u-icon name="checkmark" color="#4A90E2" size="18"></u-icon>
</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import { navigateTo } from "@/utils/uniapp";
import { ref } from "vue";
// 菜单项数据
const menuItems = ref([
{
title: "班级课表",
icon: "/static/base/home/book-read-line.png",
path: "/pages/base/class-schedule/index",
},
{
title: "在线请假",
icon: "/static/base/home/draft-line.png",
path: "/pages/base/leave-request/index",
},
{
title: "进出校园",
icon: "/static/base/home/file-transfer-line.png",
path: "/pages/base/campus-access/index",
},
{
title: "兴趣课",
icon: "/static/base/home/file-text-line.png",
path: "/pages/base/interest-class/index",
},
{
title: "俱乐部",
icon: "/static/base/home/contacts-book-3-line.png",
path: "/pages/base/club/index",
},
{
title: "成绩查询",
icon: "/static/base/home/file-search-line.png",
path: "/pages/base/grades/index",
},
]);
// 通知公告数据
const announcements = ref([
{
image: "",
title: "关于《泸州市xxxxxxxx管理办法》的通知",
description: "为规范本市就业见习管理工作,促进高校毕业生等青年...",
date: "2025-02-12 12:33:44",
},
{
image: "",
title: "关于《泸州市xxxxxxxx管理办法》的通知",
description: "为规范本市就业见习管理工作,促进高校毕业生等青年...",
date: "2025-02-12 12:33:44",
},
{
image: "",
title: "关于《泸州市xxxxxxxx管理办法》的通知",
description: "为规范本市就业见习管理工作,促进高校毕业生等青年...",
date: "2025-02-12 12:33:44",
},
]);
// 学生列表数据
const studentList = ref([
{
id: "1",
name: "陶亦菲",
grade: "2年级",
class: "01班",
avatar: "/static/base/home/11222.png",
},
{
id: "2",
name: "张小明",
grade: "4年级",
class: "03班",
avatar: "",
},
{
id: "3",
name: "王小红",
grade: "1年级",
class: "02班",
avatar: "",
},
]);
// 当前选中的学生
const currentStudent = ref(studentList.value[0]);
// 控制选择器显示状态
const showSelector = ref(false);
// 处理菜单点击
function handleMenuClick(item: any) {
console.log("点击菜单:", item.title);
if (item.path) {
uni.navigateTo({
url: item.path,
});
}
}
// 显示学生选择器
function showStudentSelector() {
showSelector.value = true;
}
// 切换学生
function switchStudent(student: any) {
currentStudent.value = student;
showSelector.value = false;
// 这里可以添加切换学生后的其他操作,如刷新页面数据等
uni.showToast({
title: `已切换到${student.name}`,
icon: "none",
});
}
</script>
<style lang="scss" scoped>
.home-page {
background-color: #ffffff;
min-height: 100vh;
position: relative;
}
.content-container {
padding: 15px;
position: relative;
z-index: 1;
}
/* 用户信息卡片 */
.user-info-card {
position: relative;
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
border-radius: 20px;
padding: 20px;
margin-bottom: 20px;
margin-top: 20px;
box-shadow: 0 12px 40px rgba(74, 144, 226, 0.25);
border: 1px solid rgba(255, 255, 255, 0.8);
overflow: hidden;
.user-content {
display: flex;
align-items: center;
position: relative;
z-index: 2;
.user-avatar {
position: relative;
width: 70px;
height: 70px;
border-radius: 50%;
overflow: hidden;
box-shadow: 0 4px 16px rgba(74, 144, 226, 0.3);
border: 3px solid #ffffff;
flex-shrink: 0;
.avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.avatar-ring {
position: absolute;
top: -3px;
left: -3px;
width: calc(100% + 6px);
height: calc(100% + 6px);
border-radius: 50%;
border: 2px solid rgba(74, 144, 226, 0.3);
animation: pulse 2s infinite;
}
}
.user-details {
flex: 1;
margin-left: 15px;
display: flex;
flex-direction: column;
justify-content: center;
.user-name {
font-size: 18px;
font-weight: 600;
color: #303133;
margin-bottom: 8px;
line-height: 1.2;
}
.user-class-container {
display: flex;
align-items: center;
.class-tag {
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
color: #ffffff;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.3);
.user-class {
line-height: 1;
}
}
}
}
.switch-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
padding: 8px 16px;
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
color: #ffffff;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
box-shadow: 0 4px 12px rgba(74, 144, 226, 0.3);
transition: all 0.3s ease;
flex-shrink: 0;
min-width: 60px;
height: 16px;
&:active {
transform: scale(0.95);
}
text {
line-height: 1;
}
}
}
}
/* 学校横幅 */
.school-banner {
margin-bottom: 25px;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 10px 32px rgba(0, 0, 0, 0.15);
.banner-content {
position: relative;
width: 100%;
height: 160px;
.banner-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.banner-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, rgba(74, 144, 226, 0.8) 0%, rgba(53, 122, 189, 0.9) 100%);
display: flex;
align-items: center;
justify-content: center;
.banner-text {
text-align: center;
.banner-title {
font-size: 26px;
font-weight: 700;
color: #ffffff;
margin-bottom: 8px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.banner-subtitle {
font-size: 14px;
color: rgba(255, 255, 255, 0.9);
font-weight: 400;
}
}
}
}
}
/* 功能菜单 */
.menu-section {
margin-bottom: 25px;
.section-title {
display: flex;
align-items: center;
margin-bottom: 20px;
padding: 0 5px;
.title-text {
font-size: 18px;
font-weight: 600;
color: #303133;
position: relative;
padding-left: 12px;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
border-radius: 2px;
}
}
.title-line {
flex: 1;
height: 1px;
background: linear-gradient(90deg, #e0e6ed 0%, transparent 100%);
margin-left: 20px;
}
}
.grid-menu {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0;
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(74, 144, 226, 0.2);
border: 1px solid rgba(255, 255, 255, 0.8);
.grid-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px 10px;
transition: all 0.3s ease;
border-radius: 12px;
position: relative;
&:active {
transform: scale(0.95);
background-color: rgba(74, 144, 226, 0.05);
}
.grid-icon-container {
position: relative;
width: 48px;
height: 48px;
margin-bottom: 12px;
display: flex;
align-items: center;
justify-content: center;
.icon-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 12px;
background: linear-gradient(135deg, #f0f4ff 0%, #e6f0ff 100%);
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
}
.grid-icon {
position: relative;
z-index: 1;
width: 28px;
height: 28px;
object-fit: contain;
}
}
.grid-text {
font-size: 13px;
font-weight: 500;
color: #303133;
text-align: center;
line-height: 1.2;
}
}
}
}
/* 通知公告 */
.notice-section {
.section-title {
display: flex;
align-items: center;
margin-bottom: 20px;
padding: 0 5px;
.title-text {
font-size: 18px;
font-weight: 600;
color: #303133;
position: relative;
padding-left: 12px;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
border-radius: 2px;
}
}
.title-line {
flex: 1;
height: 1px;
background: linear-gradient(90deg, #e0e6ed 0%, transparent 100%);
margin-left: 20px;
}
}
.notice-list {
.notice-item {
display: flex;
align-items: flex-start;
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
padding: 18px;
margin-bottom: 12px;
border-radius: 16px;
box-shadow: 0 8px 24px rgba(74, 144, 226, 0.18);
border: 1px solid rgba(255, 255, 255, 0.8);
transition: all 0.3s ease;
&:active {
transform: translateY(-2px);
box-shadow: 0 12px 36px rgba(74, 144, 226, 0.25);
}
.notice-icon {
width: 50px;
height: 50px;
background: linear-gradient(135deg, #f0f4ff 0%, #e6f0ff 100%);
border-radius: 12px;
margin-right: 15px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
flex-shrink: 0;
}
.notice-content {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
.notice-title {
font-size: 15px;
font-weight: 600;
color: #303133;
margin-bottom: 8px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
line-height: 1.3;
}
.notice-desc {
font-size: 13px;
color: #606266;
margin-bottom: 12px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
flex: 1;
line-height: 1.4;
}
.notice-footer {
display: flex;
align-items: center;
justify-content: space-between;
.notice-date {
font-size: 12px;
color: #909399;
font-weight: 400;
line-height: 1;
}
.notice-arrow {
width: 20px;
height: 20px;
background-color: #f5f7fa;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
}
}
}
}
}
/* 学生选择器弹窗样式 */
.student-selector {
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
border-top-left-radius: 20px;
border-top-right-radius: 20px;
padding-bottom: 30px;
.selector-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #f0f2f5;
.selector-title {
font-size: 18px;
font-weight: 600;
color: #303133;
line-height: 1;
}
.close-btn {
width: 32px;
height: 32px;
background-color: #f5f7fa;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
flex-shrink: 0;
&:active {
transform: scale(0.9);
background-color: #e6e8eb;
}
}
}
.student-list {
padding: 0 20px;
.student-item {
display: flex;
align-items: center;
padding: 16px 0;
border-bottom: 1px solid #f5f7fa;
transition: all 0.3s ease;
border-radius: 12px;
margin-bottom: 8px;
&:last-child {
border-bottom: none;
margin-bottom: 0;
}
&-active {
background: linear-gradient(135deg, rgba(74, 144, 226, 0.08) 0%, rgba(53, 122, 189, 0.05) 100%);
padding: 16px 12px;
}
.student-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
border: 2px solid #ffffff;
.avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.student-info {
flex: 1;
margin-left: 15px;
display: flex;
flex-direction: column;
justify-content: center;
min-width: 0;
.student-name {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 4px;
line-height: 1.2;
}
.student-class {
font-size: 13px;
color: #606266;
font-weight: 400;
line-height: 1;
}
}
.check-icon {
width: 24px;
height: 24px;
border-radius: 50%;
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.3);
flex-shrink: 0;
}
}
}
}
/* 动画效果 */
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.7;
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式优化 */
@media (max-width: 375px) {
.content-container {
padding: 12px;
}
.user-info-card .user-content .user-avatar {
width: 60px;
height: 60px;
}
.grid-menu .grid-item {
padding: 15px 8px;
}
}
</style>