zhxy-jzd/src/pages/base/home/index.vue

815 lines
20 KiB
Vue
Raw Normal View History

2025-04-30 01:43:23 +08:00
<template>
<view class="home-page">
<view class="content-container">
<!-- 用户信息卡片 -->
<view class="user-info-card">
2025-05-30 17:22:30 +08:00
<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>
2025-06-13 15:52:25 +08:00
<view class="switch-btn" @click="showStudentSelector" v-if="studentList && studentList.length > 1">
2025-05-30 17:22:30 +08:00
<u-icon name="arrow-down" size="12" color="#fff"></u-icon>
<text>切换</text>
2025-04-30 01:43:23 +08:00
</view>
</view>
</view>
<!-- 学校横幅 -->
<view class="school-banner">
2025-05-30 17:22:30 +08:00
<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>
2025-05-06 13:03:49 +08:00
</view>
2025-04-30 01:43:23 +08:00
</view>
<!-- 功能菜单 -->
2025-05-30 17:22:30 +08:00
<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>
2025-05-06 13:03:49 +08:00
</view>
2025-04-30 01:43:23 +08:00
</view>
</view>
<!-- 通知公告 -->
<view class="notice-section">
2025-05-30 17:22:30 +08:00
<view class="section-title">
<text class="title-text">通知公告</text>
<view class="title-line"></view>
2025-04-30 01:43:23 +08:00
</view>
<view class="notice-list">
<view
v-for="(notice, index) in announcements"
:key="index"
class="notice-item"
@click="navigateTo('/pages/base/home/detail')"
>
2025-05-30 17:22:30 +08:00
<view class="notice-icon">
<u-icon name="bell" size="20" color="#4A90E2"></u-icon>
</view>
2025-04-30 01:43:23 +08:00
<view class="notice-content">
<text class="notice-title">{{ notice.title }}</text>
<text class="notice-desc">{{ notice.description }}</text>
2025-05-30 17:22:30 +08:00
<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>
2025-04-30 01:43:23 +08:00
</view>
</view>
</view>
</view>
</view>
<!-- 学生选择弹窗 -->
<u-popup
:show="showSelector"
@close="showSelector = false"
mode="bottom"
2025-05-30 17:22:30 +08:00
round="20"
2025-04-30 01:43:23 +08:00
>
<view class="student-selector">
<view class="selector-header">
<text class="selector-title">选择学生</text>
2025-05-30 17:22:30 +08:00
<view class="close-btn" @click="showSelector = false">
<u-icon name="close" size="18" color="#909399"></u-icon>
</view>
2025-04-30 01:43:23 +08:00
</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)"
>
2025-05-30 17:22:30 +08:00
<view class="student-avatar">
<image :src="student.avatar || '/static/base/home/11222.png'" class="avatar-img"></image>
</view>
2025-04-30 01:43:23 +08:00
<view class="student-info">
<text class="student-name">{{ student.name }}</text>
2025-05-30 17:22:30 +08:00
<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>
2025-04-30 01:43:23 +08:00
</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
2025-05-30 17:22:30 +08:00
import { navigateTo } from "@/utils/uniapp";
import { ref } from "vue";
2025-04-30 01:43:23 +08:00
// 菜单项数据
const menuItems = ref([
{
title: "班级课表",
2025-05-06 13:03:49 +08:00
icon: "/static/base/home/book-read-line.png",
2025-04-30 01:43:23 +08:00
path: "/pages/base/class-schedule/index",
},
{
2025-06-13 15:52:25 +08:00
title: "成绩查询",
icon: "/static/base/home/file-search-line.png",
path: "/pages/base/grades/index",
2025-04-30 01:43:23 +08:00
},
2025-06-13 15:52:25 +08:00
// {
// title: "在线请假",
// icon: "/static/base/home/draft-line.png",
// path: "/pages/base/leave-request/index",
// },
// TODO:需求待协商硬件对接
// {
// title: "进出校园",
// icon: "/static/base/home/file-transfer-line.png",
// path: "/pages/base/campus-access/index",
// },
2025-04-30 01:43:23 +08:00
{
2025-06-13 15:52:25 +08:00
title: "家校沟通",
2025-05-06 13:03:49 +08:00
icon: "/static/base/home/file-transfer-line.png",
2025-04-30 01:43:23 +08:00
path: "/pages/base/campus-access/index",
},
{
title: "兴趣课",
2025-05-06 13:03:49 +08:00
icon: "/static/base/home/file-text-line.png",
2025-04-30 01:43:23 +08:00
path: "/pages/base/interest-class/index",
},
{
title: "俱乐部",
2025-05-06 13:03:49 +08:00
icon: "/static/base/home/contacts-book-3-line.png",
2025-04-30 01:43:23 +08:00
path: "/pages/base/club/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班",
2025-05-06 13:03:49 +08:00
avatar: "/static/base/home/11222.png",
2025-04-30 01:43:23 +08:00
},
{
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 {
2025-05-30 17:22:30 +08:00
background-color: #ffffff;
2025-04-30 01:43:23 +08:00
min-height: 100vh;
position: relative;
}
.content-container {
padding: 15px;
2025-05-30 17:22:30 +08:00
position: relative;
z-index: 1;
2025-04-30 01:43:23 +08:00
}
/* 用户信息卡片 */
.user-info-card {
2025-05-30 17:22:30 +08:00
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;
}
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
.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 {
2025-04-30 01:43:23 +08:00
display: flex;
align-items: center;
2025-05-30 17:22:30 +08:00
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;
2025-04-30 01:43:23 +08:00
}
}
}
}
/* 学校横幅 */
.school-banner {
2025-05-30 17:22:30 +08:00
margin-bottom: 25px;
border-radius: 16px;
2025-04-30 01:43:23 +08:00
overflow: hidden;
2025-05-30 17:22:30 +08:00
box-shadow: 0 10px 32px rgba(0, 0, 0, 0.15);
.banner-content {
position: relative;
2025-04-30 01:43:23 +08:00
width: 100%;
2025-05-30 17:22:30 +08:00
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;
}
}
}
2025-04-30 01:43:23 +08:00
}
}
/* 功能菜单 */
2025-05-30 17:22:30 +08:00
.menu-section {
margin-bottom: 25px;
.section-title {
2025-04-30 01:43:23 +08:00
display: flex;
align-items: center;
2025-05-30 17:22:30 +08:00
margin-bottom: 20px;
padding: 0 5px;
.title-text {
font-size: 18px;
font-weight: 600;
2025-04-30 01:43:23 +08:00
color: #303133;
2025-05-30 17:22:30 +08:00
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;
}
2025-04-30 01:43:23 +08:00
}
}
}
/* 通知公告 */
.notice-section {
2025-05-30 17:22:30 +08:00
.section-title {
2025-04-30 01:43:23 +08:00
display: flex;
align-items: center;
2025-05-30 17:22:30 +08:00
margin-bottom: 20px;
padding: 0 5px;
.title-text {
font-size: 18px;
font-weight: 600;
2025-04-30 01:43:23 +08:00
color: #303133;
2025-05-30 17:22:30 +08:00
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;
2025-04-30 01:43:23 +08:00
}
}
2025-05-30 17:22:30 +08:00
2025-04-30 01:43:23 +08:00
.notice-list {
.notice-item {
display: flex;
2025-05-30 17:22:30 +08:00
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);
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
.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;
}
2025-04-30 01:43:23 +08:00
.notice-content {
flex: 1;
display: flex;
flex-direction: column;
2025-05-30 17:22:30 +08:00
min-width: 0;
2025-04-30 01:43:23 +08:00
.notice-title {
font-size: 15px;
2025-05-30 17:22:30 +08:00
font-weight: 600;
2025-04-30 01:43:23 +08:00
color: #303133;
2025-05-30 17:22:30 +08:00
margin-bottom: 8px;
2025-04-30 01:43:23 +08:00
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
2025-05-30 17:22:30 +08:00
line-height: 1.3;
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
2025-04-30 01:43:23 +08:00
.notice-desc {
font-size: 13px;
2025-05-30 17:22:30 +08:00
color: #606266;
margin-bottom: 12px;
2025-04-30 01:43:23 +08:00
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
flex: 1;
2025-05-30 17:22:30 +08:00
line-height: 1.4;
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
.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;
}
2025-04-30 01:43:23 +08:00
}
}
}
}
}
/* 学生选择器弹窗样式 */
.student-selector {
2025-05-30 17:22:30 +08:00
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
border-top-left-radius: 20px;
border-top-right-radius: 20px;
padding-bottom: 30px;
2025-04-30 01:43:23 +08:00
.selector-header {
display: flex;
justify-content: space-between;
align-items: center;
2025-05-30 17:22:30 +08:00
padding: 20px;
border-bottom: 1px solid #f0f2f5;
2025-04-30 01:43:23 +08:00
.selector-title {
2025-05-30 17:22:30 +08:00
font-size: 18px;
font-weight: 600;
2025-04-30 01:43:23 +08:00
color: #303133;
2025-05-30 17:22:30 +08:00
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;
}
2025-04-30 01:43:23 +08:00
}
}
2025-05-30 17:22:30 +08:00
2025-04-30 01:43:23 +08:00
.student-list {
2025-05-30 17:22:30 +08:00
padding: 0 20px;
2025-04-30 01:43:23 +08:00
.student-item {
display: flex;
align-items: center;
2025-05-30 17:22:30 +08:00
padding: 16px 0;
border-bottom: 1px solid #f5f7fa;
transition: all 0.3s ease;
border-radius: 12px;
margin-bottom: 8px;
2025-04-30 01:43:23 +08:00
&:last-child {
border-bottom: none;
2025-05-30 17:22:30 +08:00
margin-bottom: 0;
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
2025-04-30 01:43:23 +08:00
&-active {
2025-05-30 17:22:30 +08:00
background: linear-gradient(135deg, rgba(74, 144, 226, 0.08) 0%, rgba(53, 122, 189, 0.05) 100%);
padding: 16px 12px;
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
.student-avatar {
width: 50px;
height: 50px;
2025-04-30 01:43:23 +08:00
border-radius: 50%;
2025-05-30 17:22:30 +08:00
overflow: hidden;
2025-04-30 01:43:23 +08:00
flex-shrink: 0;
2025-05-30 17:22:30 +08:00
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
border: 2px solid #ffffff;
.avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
}
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
2025-04-30 01:43:23 +08:00
.student-info {
flex: 1;
2025-05-30 17:22:30 +08:00
margin-left: 15px;
display: flex;
flex-direction: column;
justify-content: center;
min-width: 0;
2025-04-30 01:43:23 +08:00
.student-name {
2025-05-30 17:22:30 +08:00
font-size: 16px;
font-weight: 600;
2025-04-30 01:43:23 +08:00
color: #303133;
margin-bottom: 4px;
2025-05-30 17:22:30 +08:00
line-height: 1.2;
2025-04-30 01:43:23 +08:00
}
2025-05-30 17:22:30 +08:00
2025-04-30 01:43:23 +08:00
.student-class {
font-size: 13px;
color: #606266;
2025-05-30 17:22:30 +08:00
font-weight: 400;
line-height: 1;
2025-04-30 01:43:23 +08:00
}
}
2025-05-30 17:22:30 +08:00
.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;
}
2025-04-30 01:43:23 +08:00
}
}
}
2025-05-30 17:22:30 +08:00
/* 动画效果 */
@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;
}
}
2025-04-30 01:43:23 +08:00
</style>