菜单布局等初步完成

This commit is contained in:
2025-10-08 14:11:54 +08:00
parent d9ea2e842b
commit 4bc587ecf5
29 changed files with 4472 additions and 11977 deletions

View File

@@ -0,0 +1,472 @@
<template>
<div class="home-page">
<!-- 主横幅 -->
<section class="hero-section">
<div class="container">
<div class="hero-content">
<h1 class="hero-title">校园新闻管理系统</h1>
<p class="hero-subtitle">及时发布高效管理便捷浏览</p>
<div class="hero-actions">
<el-button type="primary" size="large" @click="exploreNews">
浏览新闻
</el-button>
<el-button size="large" @click="goToLogin" v-if="!isLoggedIn">
开始使用
</el-button>
</div>
</div>
</div>
</section>
<!-- 功能特性 -->
<section class="features-section">
<div class="container">
<h2 class="section-title">核心功能</h2>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">📰</div>
<h3>新闻发布</h3>
<p>快速发布校园新闻支持富文本编辑图文并茂</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔐</div>
<h3>权限管理</h3>
<p>细粒度权限控制安全可靠的用户管理体系</p>
</div>
<div class="feature-card">
<div class="feature-icon">📊</div>
<h3>数据统计</h3>
<p>实时统计新闻浏览量数据可视化展示</p>
</div>
<div class="feature-card">
<div class="feature-icon">💬</div>
<h3>评论互动</h3>
<p>支持新闻评论增强师生互动交流</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔍</div>
<h3>智能搜索</h3>
<p>全文搜索快速定位所需新闻内容</p>
</div>
<div class="feature-card">
<div class="feature-icon">📱</div>
<h3>响应式设计</h3>
<p>完美适配各种设备随时随地浏览</p>
</div>
</div>
</div>
</section>
<!-- 最新新闻 -->
<section class="news-section">
<div class="container">
<h2 class="section-title">最新新闻</h2>
<div class="news-grid">
<div class="news-card" v-for="item in latestNews" :key="item.id">
<div class="news-image">
<img :src="item.image" :alt="item.title" />
</div>
<div class="news-content">
<span class="news-category">{{ item.category }}</span>
<h3 class="news-title">{{ item.title }}</h3>
<p class="news-excerpt">{{ item.excerpt }}</p>
<div class="news-meta">
<span class="news-date">{{ item.date }}</span>
<span class="news-views">👁 {{ item.views }}</span>
</div>
</div>
</div>
</div>
<div class="news-more">
<el-button @click="exploreNews">查看更多新闻</el-button>
</div>
</div>
</section>
<!-- 页脚 -->
<footer class="home-footer">
<div class="container">
<div class="footer-content">
<div class="footer-section">
<h4>关于我们</h4>
<p>校园新闻管理系统致力于为学校提供高效便捷的新闻发布和管理平台</p>
</div>
<div class="footer-section">
<h4>快速链接</h4>
<ul>
<li><a href="#home">首页</a></li>
<li><a href="#news">新闻中心</a></li>
<li><a href="#about">关于我们</a></li>
<li><a href="#contact">联系我们</a></li>
</ul>
</div>
<div class="footer-section">
<h4>联系方式</h4>
<ul>
<li>📧 Email: info@school-news.com</li>
<li>📞 电话: 123-456-7890</li>
<li>📍 地址: XX市XX区XX路XX号</li>
</ul>
</div>
</div>
<div class="footer-bottom">
<p>© 2025 校园新闻管理系统. All rights reserved.</p>
</div>
</div>
</footer>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
import { ElMessage } from 'element-plus';
const router = useRouter();
const store = useStore();
// 计算属性
const isLoggedIn = computed(() => store.getters['auth/isAuthenticated']);
const userName = computed(() => {
const userInfo = store.getters['auth/userInfo'];
return userInfo?.userName || userInfo?.nickName || '用户';
});
// 最新新闻数据(示例)
const latestNews = ref([
{
id: 1,
title: '我校在全国大学生创新创业大赛中获得金奖',
excerpt: '在刚刚结束的第十届全国大学生创新创业大赛中,我校代表队凭借优异的表现,荣获金奖...',
category: '校园动态',
image: 'https://picsum.photos/400/250?random=1',
date: '2025-10-08',
views: 1523
},
{
id: 2,
title: '校园文化艺术节圆满落幕',
excerpt: '历时一周的校园文化艺术节于昨日圆满落幕本次艺术节共举办了20余场精彩活动...',
category: '文化活动',
image: 'https://picsum.photos/400/250?random=2',
date: '2025-10-07',
views: 2341
},
{
id: 3,
title: '学校图书馆新增电子资源数据库',
excerpt: '为了更好地服务师生科研和学习,学校图书馆新增了多个电子资源数据库...',
category: '通知公告',
image: 'https://picsum.photos/400/250?random=3',
date: '2025-10-06',
views: 987
}
]);
// 方法
function goToLogin() {
router.push('/login');
}
function goToRegister() {
router.push('/register');
}
function goToDashboard() {
router.push('/dashboard');
}
async function handleLogout() {
try {
await store.dispatch('auth/logout');
ElMessage.success('已退出登录');
} catch (error) {
console.error('退出失败:', error);
ElMessage.error('退出失败');
}
}
function exploreNews() {
// TODO: 跳转到新闻列表页
ElMessage.info('新闻列表功能开发中...');
}
// 页面加载
onMounted(() => {
// 可以在这里加载真实的新闻数据
console.log('Home page mounted');
});
</script>
<style lang="scss" scoped>
.home-page {
min-height: 100vh;
background: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
/* 主横幅 */
.hero-section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 100px 0;
text-align: center;
}
.hero-content {
max-width: 800px;
margin: 0 auto;
}
.hero-title {
font-size: 48px;
font-weight: 700;
margin: 0 0 20px 0;
}
.hero-subtitle {
font-size: 24px;
margin: 0 0 40px 0;
opacity: 0.9;
}
.hero-actions {
display: flex;
gap: 16px;
justify-content: center;
}
/* 功能特性 */
.features-section {
padding: 80px 0;
background: white;
}
.section-title {
text-align: center;
font-size: 36px;
font-weight: 600;
margin: 0 0 60px 0;
color: #333;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 32px;
}
.feature-card {
text-align: center;
padding: 32px;
background: #f9f9f9;
border-radius: 8px;
transition: transform 0.3s, box-shadow 0.3s;
&:hover {
transform: translateY(-8px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 48px;
margin-bottom: 16px;
}
h3 {
font-size: 20px;
margin: 0 0 12px 0;
color: #333;
}
p {
color: #666;
line-height: 1.6;
margin: 0;
}
}
/* 最新新闻 */
.news-section {
padding: 80px 0;
background: #f5f5f5;
}
.news-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 32px;
margin-bottom: 40px;
}
.news-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s, box-shadow 0.3s;
cursor: pointer;
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
}
.news-image {
width: 100%;
height: 200px;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s;
}
&:hover img {
transform: scale(1.1);
}
}
.news-content {
padding: 20px;
}
.news-category {
display: inline-block;
padding: 4px 12px;
background: #e6f7ff;
color: #1890ff;
border-radius: 4px;
font-size: 12px;
margin-bottom: 12px;
}
.news-title {
font-size: 18px;
font-weight: 600;
margin: 0 0 12px 0;
color: #333;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.news-excerpt {
color: #666;
font-size: 14px;
line-height: 1.6;
margin: 0 0 16px 0;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.news-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
color: #999;
}
.news-more {
text-align: center;
}
/* 页脚 */
.home-footer {
background: #001529;
color: white;
padding: 60px 0 20px 0;
margin-top: auto;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 40px;
margin-bottom: 40px;
}
.footer-section {
h4 {
font-size: 18px;
margin: 0 0 20px 0;
color: #1890ff;
}
p {
color: rgba(255, 255, 255, 0.8);
line-height: 1.6;
}
ul {
list-style: none;
padding: 0;
margin: 0;
li {
margin-bottom: 12px;
a {
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
transition: color 0.3s;
&:hover {
color: #1890ff;
}
}
}
}
}
.footer-bottom {
text-align: center;
padding-top: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.6);
}
/* 响应式设计 */
@media (max-width: 768px) {
.nav-menu {
display: none;
}
.hero-title {
font-size: 32px;
}
.hero-subtitle {
font-size: 18px;
}
.features-grid,
.news-grid {
grid-template-columns: 1fr;
}
.section-title {
font-size: 28px;
}
}
</style>

View File

@@ -141,12 +141,12 @@ const handleLogin = async () => {
loginLoading.value = true;
// 调用store中的登录action
await store.dispatch('auth/login', loginForm);
const result = await store.dispatch('auth/login', loginForm);
ElMessage.success('登录成功!');
// 获取重定向路径
const redirectPath = (route.query.redirect as string) || '/dashboard';
// 优先使用 query 中的 redirect其次使用返回的 redirectUrl最后使用默认首页
const redirectPath = (route.query.redirect as string) || result.redirectUrl || '/home';
router.push(redirectPath);
} catch (error: any) {

View File

@@ -0,0 +1,13 @@
<template>
<div>
部门管理
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>