ZhangQiPro/src/views/Login.vue
sladro 3c19173c24 feat: 优化BigScreenPortrait大屏页面显示和功能完善
🔧 显示问题修复:
- 修复参与学生人数显示布局问题,优化number-gauge-combined容器
- 调整迷你仪表盘尺寸从60px到45px,适配紧凑布局
- 优化数字显示样式,使用clamp()确保响应式适配
- 完善ECharts仪表盘配置,简化为迷你版本显示

🎯 功能按钮完善:
- 实现"生成报告"和"历史记录"按钮完整功能
- 集成权限验证系统,需要教师权限才能访问
- 添加智能权限提示,未登录时引导用户登录
- 保持按钮原有美观样式,权限不足时仅显示小锁图标

🎨 界面文本优化:
- 清理Login.vue中的"演示"字样,改为"登录"
- 移除版权信息中的"演示版本"标识
- 优化组件中的演示相关文本,提升专业性

🚀 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-16 10:23:36 +08:00

505 lines
11 KiB
Vue

<template>
<div class="login-page">
<!-- 左侧品牌展示区 -->
<div class="brand-section">
<div class="brand-content">
<!-- Logo和标题 -->
<div class="brand-header">
<div class="logo">
<School :size="24" />
</div>
<h1 class="brand-title">实践教学评价平台</h1>
<p class="brand-subtitle">智能化多角色协同评价系统</p>
</div>
<!-- 统计数据展示 -->
<div class="stats-grid">
<div class="stat-item">
<div class="stat-number">1,234</div>
<div class="stat-label">注册学生</div>
</div>
<div class="stat-item">
<div class="stat-number">156</div>
<div class="stat-label">在线课程</div>
</div>
<div class="stat-item">
<div class="stat-number">8,567</div>
<div class="stat-label">完成评价</div>
</div>
<div class="stat-item">
<div class="stat-number">98%</div>
<div class="stat-label">满意度</div>
</div>
</div>
<!-- 装饰性元素 -->
<div class="brand-decoration">
<svg viewBox="0 0 400 200" class="wave-svg">
<path d="M0,100 C100,20 200,180 400,100 L400,200 L0,200 Z" fill="rgba(255,255,255,0.1)"/>
</svg>
</div>
</div>
</div>
<!-- 右侧登录区域 -->
<div class="login-section">
<div class="login-container">
<div class="login-header">
<h2>欢迎回来</h2>
<p>请登录您的账户继续使用</p>
</div>
<div class="login-card">
<el-form
ref="loginForm"
:model="form"
:rules="rules"
class="login-form"
>
<el-form-item prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
size="large"
clearable
>
<template #prefix>
<User class="input-icon" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="form.password"
type="password"
placeholder="请输入密码"
size="large"
clearable
show-password
>
<template #prefix>
<Lock class="input-icon" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="role">
<el-select
v-model="form.role"
placeholder="请选择您的角色"
size="large"
class="full-width"
>
<el-option label="学生" value="student" />
<el-option label="教师" value="teacher" />
<el-option label="企业" value="company" />
<el-option label="行业协会专家" value="expert" />
</el-select>
</el-form-item>
<el-button
type="primary"
size="large"
:loading="loading"
@click="handleLogin"
class="login-btn"
>
登录系统
</el-button>
</el-form>
<div class="quick-login">
<div class="divider">
<span>快速体验</span>
</div>
<div class="demo-buttons">
<button class="demo-btn" @click="quickLogin('student')" style="padding: 10px var(--spacing-md);">
<el-icon style="font-size: 14px; margin-right: 6px;"><User /></el-icon>
学生登录
</button>
<button class="demo-btn" @click="quickLogin('teacher')" style="padding: 10px var(--spacing-md);">
<el-icon style="font-size: 14px; margin-right: 6px;"><Monitor /></el-icon>
教师登录
</button>
</div>
<div class="demo-buttons" style="margin-top: 8px;">
<button class="demo-btn big-screen-btn" @click="$router.push('/big-screen-portrait')" style="flex: none; width: 100%; padding: 10px var(--spacing-md);">
<el-icon style="font-size: 14px; margin-right: 6px;"><PieChart /></el-icon>
学生能力评价画像
</button>
</div>
</div>
</div>
<div class="login-footer">
<p>&copy; 2024 实践教学评价平台</p>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { useAuthStore } from '@/stores/auth'
import { mockUsers } from '@/utils/mockData'
export default {
name: 'Login',
setup() {
const router = useRouter()
const authStore = useAuthStore()
const form = reactive({
username: '',
password: '',
role: ''
})
const rules = {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
role: [{ required: true, message: '请选择角色', trigger: 'change' }]
}
const loading = ref(false)
const loginForm = ref(null)
const handleLogin = async () => {
await loginForm.value.validate()
loading.value = true
// 模拟登录验证
const user = mockUsers.find(u =>
u.username === form.username &&
u.password === form.password &&
u.role === form.role
)
if (user) {
authStore.login(user)
ElMessage.success('登录成功')
router.push('/home')
} else {
ElMessage.error('用户名或密码错误')
}
loading.value = false
}
const quickLogin = (role) => {
if (role === 'student') {
form.username = 'student1'
form.password = '123456'
form.role = 'student'
} else if (role === 'teacher') {
form.username = 'teacher1'
form.password = '123456'
form.role = 'teacher'
}
}
return {
form,
rules,
loading,
loginForm,
handleLogin,
quickLogin
}
}
}
</script>
<style scoped>
.login-page {
min-height: 100vh;
display: flex;
}
/* 左侧品牌展示区 */
.brand-section {
flex: 1;
background: var(--gradient-brand);
color: var(--text-inverse);
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.brand-content {
padding: var(--spacing-xxl);
text-align: center;
position: relative;
z-index: 2;
width: 100%;
max-width: 500px;
}
.brand-header {
margin-bottom: var(--spacing-xxl);
}
.logo {
width: 48px;
height: 48px;
background: var(--white-alpha-lighter);
border-radius: var(--radius-xl);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto var(--spacing-lg);
color: white;
backdrop-filter: blur(10px);
}
.brand-title {
font-size: calc(var(--font-size-xxl) * 1.3);
font-weight: 800;
margin-bottom: var(--spacing-md);
line-height: 1.2;
}
.brand-subtitle {
font-size: var(--font-size-lg);
opacity: 0.9;
margin-bottom: 0;
font-weight: 400;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-lg);
margin-bottom: var(--spacing-xxl);
}
.stat-item {
background: var(--white-alpha-lighter);
padding: var(--spacing-lg);
border-radius: var(--radius-lg);
backdrop-filter: blur(10px);
border: 1px solid var(--white-alpha-lighter);
transition: var(--transition);
}
.stat-item:hover {
background: var(--white-alpha-lighter);
transform: translateY(-2px);
}
.stat-number {
font-size: var(--font-size-xxl);
font-weight: 700;
margin-bottom: var(--spacing-xs);
color: white;
}
.stat-label {
font-size: var(--font-size-sm);
opacity: 0.8;
font-weight: 500;
}
.brand-decoration {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 200px;
}
.wave-svg {
width: 100%;
height: 100%;
}
/* 右侧登录区域 */
.login-section {
flex: 0 0 450px;
background: var(--bg-primary);
display: flex;
align-items: center;
justify-content: center;
padding: var(--spacing-xxl);
}
.login-container {
width: 100%;
max-width: 400px;
}
.login-header {
text-align: center;
margin-bottom: var(--spacing-xxl);
}
.login-header h2 {
font-size: var(--font-size-xxl);
font-weight: 700;
color: var(--text-primary);
margin-bottom: var(--spacing-md);
}
.login-header p {
color: var(--text-secondary);
font-size: var(--font-size-md);
margin: 0;
}
.login-card {
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: var(--radius-xl);
padding: var(--spacing-xxl);
box-shadow: var(--shadow-lg);
margin-bottom: var(--spacing-xl);
}
.login-form .el-form-item {
margin-bottom: var(--spacing-lg);
}
.full-width {
width: 100%;
}
.input-icon {
color: var(--text-muted);
}
.login-btn {
width: 100%;
height: 44px;
background: var(--gradient-primary);
border: none;
border-radius: var(--radius-lg);
color: white;
font-size: var(--font-size-lg);
font-weight: 600;
cursor: pointer;
transition: var(--transition);
margin-top: var(--spacing-md);
}
.login-btn:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.login-btn:active {
transform: translateY(0);
}
.quick-login {
margin-top: var(--spacing-xl);
}
.divider {
text-align: center;
margin: var(--spacing-lg) 0;
position: relative;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: var(--border);
}
.divider span {
background: var(--bg-primary);
padding: 0 var(--spacing-md);
color: var(--text-muted);
font-size: var(--font-size-sm);
}
.demo-buttons {
display: flex;
gap: var(--spacing-sm);
}
.demo-btn {
flex: 1;
padding: var(--spacing-md);
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: var(--radius-md);
color: var(--text-primary);
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
gap: var(--spacing-xs);
font-size: var(--font-size-sm);
}
.demo-btn:hover {
background: var(--primary-lighter);
border-color: var(--primary);
color: var(--primary);
}
.big-screen-btn {
background: var(--gradient-primary);
color: var(--text-inverse) !important;
border-color: transparent;
font-weight: 600;
}
.big-screen-btn:hover {
background: var(--primary) !important;
border-color: transparent !important;
color: var(--text-inverse) !important;
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.login-footer {
text-align: center;
}
.login-footer p {
color: var(--text-muted);
font-size: var(--font-size-xs);
margin: 0;
}
/* 响应式设计 */
@media (max-width: 1024px) {
.login-section {
flex: 0 0 380px;
}
}
@media (max-width: 768px) {
.login-page {
flex-direction: column;
}
.brand-section {
flex: 0 0 280px;
}
.stats-grid {
grid-template-columns: repeat(4, 1fr);
gap: var(--spacing-sm);
}
.login-section {
flex: 1;
padding: var(--spacing-lg);
}
}
</style>