chore: stop tracking ignored local files
This commit is contained in:
BIN
backend/.DS_Store
vendored
BIN
backend/.DS_Store
vendored
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
^C
|
|
||||||
File diff suppressed because it is too large
Load Diff
BIN
backend/src/.DS_Store
vendored
BIN
backend/src/.DS_Store
vendored
Binary file not shown.
18
开发测试账号.md
18
开发测试账号.md
@@ -1,18 +0,0 @@
|
|||||||
# 开发测试账号
|
|
||||||
|
|
||||||
以下账号会在后端以 `dev` profile 启动时自动初始化。
|
|
||||||
|
|
||||||
## 门户账号
|
|
||||||
|
|
||||||
| 门户用户名 | 门户密码 | 教务学号 | 教务密码 | 查询学期 | 网盘示例文件 |
|
|
||||||
| --- | --- | --- | --- | --- | --- |
|
|
||||||
| `portal-demo` | `portal123456` | `2023123456` | `portal123456` | `2025-spring` | `迎新资料.txt`、`课程规划.md`、`campus-shot.png` |
|
|
||||||
| `portal-study` | `study123456` | `2022456789` | `study123456` | `2024-fall` | `实验数据.csv`、`论文草稿.md`、`data-chart.png` |
|
|
||||||
| `portal-design` | `design123456` | `2021789012` | `design123456` | `2024-spring` | `素材清单.txt`、`作品说明.md`、`ui-mockup.png` |
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
|
|
||||||
- 先用上表中的“门户用户名 / 门户密码”登录站点。
|
|
||||||
- 登录后进入网盘页,每个用户都会看到自己的 `下载 / 文档 / 图片` 目录,以及各自不同的样例文件。
|
|
||||||
- 进入教务页后,填入对应的“教务学号 / 教务密码 / 查询学期”即可看到该用户对应的 mock 教务数据。
|
|
||||||
- 当前开发环境的教务密码字段仅用于前端占位,后端主要依据登录态、学号和学期返回该用户的 mock 数据。为避免混淆,直接填表中的教务密码即可。
|
|
||||||
261
模板/Login.tsx
261
模板/Login.tsx
@@ -1,261 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { motion, AnimatePresence } from 'motion/react';
|
|
||||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/src/components/ui/card';
|
|
||||||
import { Button } from '@/src/components/ui/button';
|
|
||||||
import { Input } from '@/src/components/ui/input';
|
|
||||||
import { LogIn, User, Lock, UserPlus, Mail, ArrowLeft } from 'lucide-react';
|
|
||||||
import { cn } from '@/src/lib/utils';
|
|
||||||
|
|
||||||
export default function Login() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [isLogin, setIsLogin] = useState(true);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [error, setError] = useState('');
|
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setLoading(true);
|
|
||||||
setError('');
|
|
||||||
|
|
||||||
// Simulate auth
|
|
||||||
setTimeout(() => {
|
|
||||||
setLoading(false);
|
|
||||||
if (isLogin) {
|
|
||||||
navigate('/overview');
|
|
||||||
} else {
|
|
||||||
setIsLogin(true); // Switch back to login after "registering"
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen flex items-center justify-center bg-[#07101D] relative overflow-hidden">
|
|
||||||
{/* Background Glow */}
|
|
||||||
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-[#336EFF] rounded-full mix-blend-screen filter blur-[128px] opacity-20 animate-pulse" />
|
|
||||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-purple-600 rounded-full mix-blend-screen filter blur-[128px] opacity-20" />
|
|
||||||
|
|
||||||
<div className="container mx-auto px-4 relative z-10 flex items-center w-full min-h-[600px]">
|
|
||||||
{/* Left Side: Brand Info (Only visible in Login mode) */}
|
|
||||||
<AnimatePresence>
|
|
||||||
{isLogin && (
|
|
||||||
<motion.div
|
|
||||||
key="brand-info"
|
|
||||||
initial={{ opacity: 0, x: -50 }}
|
|
||||||
animate={{ opacity: 1, x: 0 }}
|
|
||||||
exit={{ opacity: 0, x: -50 }}
|
|
||||||
transition={{ duration: 0.5, ease: 'easeOut' }}
|
|
||||||
className="absolute left-4 lg:left-8 xl:left-12 w-1/2 max-w-lg hidden lg:flex flex-col space-y-6"
|
|
||||||
>
|
|
||||||
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full glass-panel border-white/10 w-fit">
|
|
||||||
<span className="w-2 h-2 rounded-full bg-[#336EFF] animate-pulse" />
|
|
||||||
<span className="text-sm text-slate-300 font-medium tracking-wide uppercase">Access Portal</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-2">
|
|
||||||
<h2 className="text-xl text-[#336EFF] font-bold tracking-widest uppercase">YOYUZH.XYZ</h2>
|
|
||||||
<h1 className="text-5xl md:text-6xl font-bold text-white leading-tight">
|
|
||||||
个人网站<br />统一入口
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className="text-lg text-slate-400 leading-relaxed">
|
|
||||||
欢迎来到 YOYUZH 的个人门户。在这里,你可以集中管理个人网盘文件、查询教务成绩课表,以及体验轻量级小游戏。
|
|
||||||
</p>
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
|
||||||
|
|
||||||
{/* Form Container */}
|
|
||||||
<motion.div
|
|
||||||
layout
|
|
||||||
transition={{ type: 'spring', stiffness: 200, damping: 25 }}
|
|
||||||
className={cn(
|
|
||||||
"w-full max-w-md z-10",
|
|
||||||
isLogin ? "ml-auto lg:mr-8 xl:mr-12" : "mx-auto"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Card className="border-white/10 backdrop-blur-2xl bg-white/5 shadow-2xl overflow-hidden">
|
|
||||||
<AnimatePresence mode="wait">
|
|
||||||
{isLogin ? (
|
|
||||||
<motion.div
|
|
||||||
key="login-form"
|
|
||||||
initial={{ opacity: 0, x: 20 }}
|
|
||||||
animate={{ opacity: 1, x: 0 }}
|
|
||||||
exit={{ opacity: 0, x: -20 }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
>
|
|
||||||
<CardHeader className="space-y-1 pb-8">
|
|
||||||
<CardTitle className="text-2xl font-bold text-white flex items-center gap-2">
|
|
||||||
<LogIn className="w-6 h-6 text-[#336EFF]" />
|
|
||||||
登录
|
|
||||||
</CardTitle>
|
|
||||||
<CardDescription className="text-slate-400">
|
|
||||||
请输入您的账号和密码以继续
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-slate-300 ml-1">用户名</label>
|
|
||||||
<div className="relative">
|
|
||||||
<User className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
placeholder="账号 / 用户名 / 学号"
|
|
||||||
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-slate-300 ml-1">密码</label>
|
|
||||||
<div className="relative">
|
|
||||||
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
placeholder="••••••••"
|
|
||||||
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error && (
|
|
||||||
<div className="p-3 rounded-xl bg-red-500/10 border border-red-500/20 text-red-400 text-sm">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
className="w-full h-12 text-base font-semibold"
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<span className="flex items-center gap-2">
|
|
||||||
<span className="w-4 h-4 border-2 border-white/20 border-t-white rounded-full animate-spin" />
|
|
||||||
登录中...
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
'进入系统'
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<div className="text-center">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setIsLogin(false)}
|
|
||||||
className="text-sm text-slate-400 hover:text-[#336EFF] transition-colors"
|
|
||||||
>
|
|
||||||
还没有账号?立即注册
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</CardContent>
|
|
||||||
</motion.div>
|
|
||||||
) : (
|
|
||||||
<motion.div
|
|
||||||
key="register-form"
|
|
||||||
initial={{ opacity: 0, x: 20 }}
|
|
||||||
animate={{ opacity: 1, x: 0 }}
|
|
||||||
exit={{ opacity: 0, x: -20 }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
>
|
|
||||||
<CardHeader className="space-y-1 pb-8">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<CardTitle className="text-2xl font-bold text-white flex items-center gap-2">
|
|
||||||
<UserPlus className="w-6 h-6 text-[#336EFF]" />
|
|
||||||
注册账号
|
|
||||||
</CardTitle>
|
|
||||||
<button
|
|
||||||
onClick={() => setIsLogin(true)}
|
|
||||||
className="p-2 rounded-full hover:bg-white/5 text-slate-400 transition-colors"
|
|
||||||
>
|
|
||||||
<ArrowLeft className="w-5 h-5" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<CardDescription className="text-slate-400">
|
|
||||||
创建一个新账号以开启您的门户体验
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-slate-300 ml-1">用户名</label>
|
|
||||||
<div className="relative">
|
|
||||||
<User className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
placeholder="设置您的用户名"
|
|
||||||
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-slate-300 ml-1">邮箱</label>
|
|
||||||
<div className="relative">
|
|
||||||
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
|
|
||||||
<Input
|
|
||||||
type="email"
|
|
||||||
placeholder="your@email.com"
|
|
||||||
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-slate-300 ml-1">密码</label>
|
|
||||||
<div className="relative">
|
|
||||||
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
placeholder="设置您的密码"
|
|
||||||
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
className="w-full h-12 text-base font-semibold"
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<span className="flex items-center gap-2">
|
|
||||||
<span className="w-4 h-4 border-2 border-white/20 border-t-white rounded-full animate-spin" />
|
|
||||||
注册中...
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
'创建账号'
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<div className="text-center">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setIsLogin(true)}
|
|
||||||
className="text-sm text-slate-400 hover:text-[#336EFF] transition-colors"
|
|
||||||
>
|
|
||||||
已有账号?返回登录
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</CardContent>
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
|
||||||
</Card>
|
|
||||||
</motion.div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="style.css">
|
|
||||||
<title>html+css实现漂亮的透明动态漂浮登录页面</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<section>
|
|
||||||
<!-- 背景颜色 -->
|
|
||||||
<div class="color"></div>
|
|
||||||
<div class="color"></div>
|
|
||||||
<div class="color"></div>
|
|
||||||
<div class="box">
|
|
||||||
<!-- 背景圆 -->
|
|
||||||
<div class="circle" style="--x:0"></div>
|
|
||||||
<div class="circle" style="--x:1"></div>
|
|
||||||
<div class="circle" style="--x:2"></div>
|
|
||||||
<div class="circle" style="--x:3"></div>
|
|
||||||
<div class="circle" style="--x:4"></div>
|
|
||||||
<!-- 登录框 -->
|
|
||||||
<div class="container">
|
|
||||||
<div class="form">
|
|
||||||
<h2>登录</h2>
|
|
||||||
<form>
|
|
||||||
<div class="inputBox">
|
|
||||||
<input type="text" placeholder="姓名">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="inputBox">
|
|
||||||
<input type="password" placeholder="密码">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="inputBox">
|
|
||||||
<input type="submit" value="登录">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<p class="forget">忘记密码?<a href="#">
|
|
||||||
点击这里
|
|
||||||
</a></p>
|
|
||||||
<p class="forget">没有账户?<a href="#">
|
|
||||||
注册
|
|
||||||
</a></p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
236
模板/style.css
236
模板/style.css
@@ -1,236 +0,0 @@
|
|||||||
/* 清除浏览器默认边距,
|
|
||||||
使边框和内边距的值包含在元素的width和height内 */
|
|
||||||
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 使用flex布局,让内容垂直和水平居中 */
|
|
||||||
|
|
||||||
section {
|
|
||||||
/* 相对定位 */
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 100vh;
|
|
||||||
/* linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片 */
|
|
||||||
background: linear-gradient(to bottom, #f1f4f9, #dff1ff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 背景颜色 */
|
|
||||||
|
|
||||||
section .color {
|
|
||||||
/* 绝对定位 */
|
|
||||||
position: absolute;
|
|
||||||
/* 使用filter(滤镜) 属性,给图像设置高斯模糊*/
|
|
||||||
filter: blur(200px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* :nth-child(n) 选择器匹配父元素中的第 n 个子元素 */
|
|
||||||
|
|
||||||
section .color:nth-child(1) {
|
|
||||||
top: -350px;
|
|
||||||
width: 600px;
|
|
||||||
height: 600px;
|
|
||||||
background: #ff359b;
|
|
||||||
}
|
|
||||||
|
|
||||||
section .color:nth-child(2) {
|
|
||||||
bottom: -150px;
|
|
||||||
left: 100px;
|
|
||||||
width: 500px;
|
|
||||||
height: 500px;
|
|
||||||
background: #fffd87;
|
|
||||||
}
|
|
||||||
|
|
||||||
section .color:nth-child(3) {
|
|
||||||
bottom: 50px;
|
|
||||||
right: 100px;
|
|
||||||
width: 500px;
|
|
||||||
height: 500px;
|
|
||||||
background: #00d2ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 背景圆样式 */
|
|
||||||
|
|
||||||
.box .circle {
|
|
||||||
position: absolute;
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
/* backdrop-filter属性为一个元素后面区域添加模糊效果 */
|
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
border-radius: 50%;
|
|
||||||
/* 使用filter(滤镜) 属性,改变颜色。
|
|
||||||
hue-rotate(deg) 给图像应用色相旋转
|
|
||||||
calc() 函数用于动态计算长度值
|
|
||||||
var() 函数调用自定义的CSS属性值x*/
|
|
||||||
filter: hue-rotate(calc(var(--x) * 70deg));
|
|
||||||
/* 调用动画animate,需要10s完成动画,
|
|
||||||
linear表示动画从头到尾的速度是相同的,
|
|
||||||
infinite指定动画应该循环播放无限次*/
|
|
||||||
animation: animate 10s linear infinite;
|
|
||||||
/* 动态计算动画延迟几秒播放 */
|
|
||||||
animation-delay: calc(var(--x) * -1s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 背景圆动画 */
|
|
||||||
|
|
||||||
@keyframes animate {
|
|
||||||
0%, 100%, {
|
|
||||||
transform: translateY(-50px);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: translateY(50px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.box .circle:nth-child(1) {
|
|
||||||
top: -50px;
|
|
||||||
right: -60px;
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box .circle:nth-child(2) {
|
|
||||||
top: 150px;
|
|
||||||
left: -100px;
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box .circle:nth-child(3) {
|
|
||||||
bottom: 50px;
|
|
||||||
right: -60px;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box .circle:nth-child(4) {
|
|
||||||
bottom: -80px;
|
|
||||||
left: 100px;
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box .circle:nth-child(5) {
|
|
||||||
top: -80px;
|
|
||||||
left: 140px;
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 登录框样式 */
|
|
||||||
|
|
||||||
.container {
|
|
||||||
position: relative;
|
|
||||||
width: 400px;
|
|
||||||
min-height: 400px;
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 登录标题样式 */
|
|
||||||
|
|
||||||
.form h2 {
|
|
||||||
position: relative;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 600;
|
|
||||||
letter-spacing: 5px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 登录标题的下划线样式 */
|
|
||||||
|
|
||||||
.form h2::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
bottom: -10px;
|
|
||||||
width: 0px;
|
|
||||||
height: 3px;
|
|
||||||
background: #fff;
|
|
||||||
transition: 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form h2:hover:before {
|
|
||||||
width: 53px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form .inputBox {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 输入框样式 */
|
|
||||||
|
|
||||||
.form .inputBox input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px 20px;
|
|
||||||
background: rgba(255, 255, 255, 0.2);
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
border-radius: 30px;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
font-size: 16px;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
color: #fff;
|
|
||||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form .inputBox input::placeholder {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 登录按钮样式 */
|
|
||||||
|
|
||||||
.form .inputBox input[type="submit"] {
|
|
||||||
background: #fff;
|
|
||||||
color: #666;
|
|
||||||
max-width: 100px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forget {
|
|
||||||
margin-top: 6px;
|
|
||||||
color: #fff;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forget a {
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 600;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
@@ -1,668 +0,0 @@
|
|||||||
# Personal Portal 前端页面需求文档
|
|
||||||
|
|
||||||
## 1. 文档说明
|
|
||||||
|
|
||||||
- 设计来源:`草图/pencil-new.pen`
|
|
||||||
- 目标:将设计稿整理为可执行的前端页面需求,供 UI 开发、接口联调、测试验收使用
|
|
||||||
- 适用范围:PC Web 端个人门户站点
|
|
||||||
- 设计基准尺寸:`1440 x 1024`
|
|
||||||
- 说明:文档中未在设计稿中直接标注但对实现必需的内容,已按常规门户产品逻辑做合理补充,并明确写为“建议”或“推断”
|
|
||||||
|
|
||||||
## 2. 产品定位
|
|
||||||
|
|
||||||
这是一个统一个人门户站点,用于集中承载以下能力:
|
|
||||||
|
|
||||||
- 账号登录
|
|
||||||
- 首页总览
|
|
||||||
- 网盘文件管理
|
|
||||||
- 教务数据查询
|
|
||||||
- 游戏入口聚合
|
|
||||||
|
|
||||||
站点风格偏深色、毛玻璃、卡片式信息展示,强调“统一入口”和“个人数据聚合”。
|
|
||||||
|
|
||||||
## 3. 站点信息架构
|
|
||||||
|
|
||||||
建议前端按以下一级路由组织:
|
|
||||||
|
|
||||||
| 页面 | 建议路由 | 页面目标 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 登录页 | `/login` | 完成身份认证并进入门户 |
|
|
||||||
| 总览页 | `/overview` | 汇总展示用户、文件、课程、成绩等核心信息 |
|
|
||||||
| 网盘页 | `/files` | 浏览、筛选、查看和上传个人文件 |
|
|
||||||
| 教务页 | `/school` | 查询课表、成绩并展示学期数据 |
|
|
||||||
| 游戏页 | `/games` | 提供小游戏入口和分类切换 |
|
|
||||||
|
|
||||||
## 4. 全局设计与交互要求
|
|
||||||
|
|
||||||
### 4.1 全局视觉规范
|
|
||||||
|
|
||||||
- 页面主背景为深蓝黑色系,建议主背景色接近 `#07101D`
|
|
||||||
- 卡片、导航、输入框采用半透明深色背景叠加模糊效果,形成毛玻璃风格
|
|
||||||
- 主强调色为亮蓝色,建议主色接近 `#336EFF`
|
|
||||||
- 文字颜色分三级:
|
|
||||||
- 一级文字:高亮白色,用于标题、主按钮文字、关键数据
|
|
||||||
- 二级文字:浅蓝灰色,用于说明文案、次要导航
|
|
||||||
- 三级文字:更浅的透明文字,用于分隔说明和弱提示
|
|
||||||
- 整站圆角统一偏大,按钮、卡片、胶囊标签均使用较高圆角
|
|
||||||
|
|
||||||
### 4.2 全局布局要求
|
|
||||||
|
|
||||||
- 所有页面采用顶部导航 + 主内容区结构
|
|
||||||
- 顶部导航固定在页面顶部,默认包含站点品牌和一级导航入口
|
|
||||||
- 主内容区使用卡片化分区布局,不同页面根据业务类型使用多列或多卡片排布
|
|
||||||
- 所有卡片之间需要保留清晰的间距层级,避免信息拥挤
|
|
||||||
|
|
||||||
### 4.3 全局导航要求
|
|
||||||
|
|
||||||
- 顶部左侧固定展示站点品牌:
|
|
||||||
- 主标题:`YOYUZH.XYZ`
|
|
||||||
- 副标题:`Personal Portal`
|
|
||||||
- 顶部右侧固定展示一级导航:
|
|
||||||
- 总览
|
|
||||||
- 网盘
|
|
||||||
- 教务
|
|
||||||
- 游戏
|
|
||||||
- 当前所在页面的导航项为激活态:
|
|
||||||
- 高亮蓝色背景
|
|
||||||
- 白色文字
|
|
||||||
- 带轻微发光或阴影
|
|
||||||
- 非当前页面为普通态:
|
|
||||||
- 半透明深色背景
|
|
||||||
- 浅色文字
|
|
||||||
- 点击一级导航后执行页面切换,建议保留当前登录态
|
|
||||||
|
|
||||||
### 4.4 全局交互要求
|
|
||||||
|
|
||||||
- 所有按钮、胶囊标签、切换项、列表行都应具备 hover、focus、active 状态
|
|
||||||
- 键盘 Tab 顺序必须与视觉顺序一致
|
|
||||||
- 图标型按钮若后续补充图标,必须提供 `aria-label`
|
|
||||||
- 卡片内部若有按钮组,主操作需突出显示,次操作保持弱化视觉
|
|
||||||
- 页面切换过程中应有最基本的加载保护,避免空白闪烁
|
|
||||||
|
|
||||||
### 4.5 全局状态要求
|
|
||||||
|
|
||||||
每个业务页面至少支持以下状态:
|
|
||||||
|
|
||||||
- 加载中:显示骨架屏或占位态
|
|
||||||
- 加载成功:展示设计稿对应内容
|
|
||||||
- 空状态:当列表、课表、成绩无数据时显示空态说明
|
|
||||||
- 错误状态:接口失败时显示错误提示与重试入口
|
|
||||||
- 未登录状态:除登录页外,若无有效登录态应跳回登录页
|
|
||||||
|
|
||||||
### 4.6 响应式要求
|
|
||||||
|
|
||||||
设计稿是桌面端稿件,前端实现时建议补齐以下断点:
|
|
||||||
|
|
||||||
- `>= 1280px`:按设计稿布局展示
|
|
||||||
- `768px - 1279px`:多列卡片可改为 2 列,右侧预览或抽屉可下移
|
|
||||||
- `< 768px`:顶部导航压缩为可滚动标签或抽屉菜单;卡片全部改为单列堆叠
|
|
||||||
|
|
||||||
移动端适配要求:
|
|
||||||
|
|
||||||
- 不允许出现横向滚动条
|
|
||||||
- 卡片内文字不可溢出遮挡
|
|
||||||
- 按钮点击热区不小于 `44 x 44px`
|
|
||||||
- 文件表格在小屏下可切换为列表卡片模式
|
|
||||||
|
|
||||||
### 4.7 可访问性要求
|
|
||||||
|
|
||||||
- 文本与背景对比度满足基本可读性
|
|
||||||
- 表单字段必须带标签
|
|
||||||
- 所有可点击控件需支持键盘操作
|
|
||||||
- 当前导航项、当前分段切换项需要有明确的选中态
|
|
||||||
- 动画需兼容 `prefers-reduced-motion`
|
|
||||||
|
|
||||||
## 5. 登录页需求
|
|
||||||
|
|
||||||
### 5.1 页面目标
|
|
||||||
|
|
||||||
为用户提供统一入口,完成账号认证并进入门户首页。
|
|
||||||
|
|
||||||
### 5.2 页面结构
|
|
||||||
|
|
||||||
页面分为左右两区:
|
|
||||||
|
|
||||||
- 左侧品牌介绍区
|
|
||||||
- 右侧登录表单区
|
|
||||||
|
|
||||||
### 5.3 左侧品牌介绍区
|
|
||||||
|
|
||||||
应包含以下元素:
|
|
||||||
|
|
||||||
- 品牌标题:`YOYUZH.XYZ`
|
|
||||||
- 品牌副标题:`Personal Portal`
|
|
||||||
- 胶囊标签:`Access Portal`
|
|
||||||
- 主标题:`个人网站统一入口`
|
|
||||||
- 一段站点简介文案
|
|
||||||
|
|
||||||
实现要求:
|
|
||||||
|
|
||||||
- 左侧内容垂直排列,整体偏页面左上区域
|
|
||||||
- 背景需要有大面积柔和发光装饰,营造氛围感
|
|
||||||
- 简介文案允许后续替换为真实站点介绍
|
|
||||||
|
|
||||||
### 5.4 右侧登录表单区
|
|
||||||
|
|
||||||
表单卡片应包含以下字段和元素:
|
|
||||||
|
|
||||||
- 表单标题:`登录`
|
|
||||||
- 用户名输入框
|
|
||||||
- 密码输入框
|
|
||||||
- 主按钮:`进入系统`
|
|
||||||
|
|
||||||
字段要求:
|
|
||||||
|
|
||||||
| 字段 | 类型 | 必填 | 说明 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 用户名 | 文本输入 | 是 | 支持账号、用户名或学号 |
|
|
||||||
| 密码 | 密码输入 | 是 | 采用掩码显示 |
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 用户名、密码均为空时点击按钮,给出必填校验
|
|
||||||
- 支持按 Enter 提交表单
|
|
||||||
- 登录请求发起后按钮进入 loading 状态并禁用重复点击
|
|
||||||
- 登录成功后跳转至 `/overview`
|
|
||||||
- 登录失败时在表单区域显示错误提示
|
|
||||||
|
|
||||||
建议补充能力:
|
|
||||||
|
|
||||||
- 记住登录状态
|
|
||||||
- 登录态过期自动跳转登录页
|
|
||||||
- 允许后续增加验证码或二次验证
|
|
||||||
|
|
||||||
### 5.5 登录页验收标准
|
|
||||||
|
|
||||||
- 页面首屏能清晰表达“统一入口”的产品定位
|
|
||||||
- 输入框、按钮在视觉上与整体毛玻璃风格统一
|
|
||||||
- 表单校验、提交、错误反馈完整
|
|
||||||
- 登录成功跳转逻辑正常
|
|
||||||
|
|
||||||
## 6. 总览页需求
|
|
||||||
|
|
||||||
### 6.1 页面目标
|
|
||||||
|
|
||||||
集中展示用户最常用的跨模块摘要信息,让用户在一个页面看到文件、课程、成绩、账号等核心状态。
|
|
||||||
|
|
||||||
### 6.2 页面结构
|
|
||||||
|
|
||||||
总览页包含以下模块:
|
|
||||||
|
|
||||||
- 顶部导航栏
|
|
||||||
- 欢迎 Hero 区
|
|
||||||
- 4 张数据指标卡片
|
|
||||||
- 最近文件卡片
|
|
||||||
- 今日 / 本周课程卡片
|
|
||||||
- 快捷操作卡片
|
|
||||||
- 存储空间卡片
|
|
||||||
- 账号信息卡片
|
|
||||||
|
|
||||||
### 6.3 Hero 欢迎区
|
|
||||||
|
|
||||||
需展示以下内容:
|
|
||||||
|
|
||||||
- 欢迎语:如 `欢迎回来,tester5595`
|
|
||||||
- 当前时间与问候语:如 `现在时间 20:17 · 晚上好`
|
|
||||||
- 简短页面说明
|
|
||||||
|
|
||||||
实现要求:
|
|
||||||
|
|
||||||
- 欢迎语作为页面最强视觉标题
|
|
||||||
- 当前时间应来自前端运行时或服务端返回,不应硬编码
|
|
||||||
- 问候语应根据时间段变化,建议分为凌晨、早上、下午、晚上
|
|
||||||
|
|
||||||
### 6.4 指标卡片区
|
|
||||||
|
|
||||||
共 4 个指标模块:
|
|
||||||
|
|
||||||
| 模块 | 示例值 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 网盘文件总数 | `128` | 展示文件总量及分类说明 |
|
|
||||||
| 最近 7 天上传 | `6` | 展示近 7 日上传数量和最近更新时间 |
|
|
||||||
| 本周课程 | `18` | 展示本周课程总量及今日课节数 |
|
|
||||||
| 已录入成绩 | `42` | 展示成绩总数及最近学期 |
|
|
||||||
|
|
||||||
实现要求:
|
|
||||||
|
|
||||||
- 数字需突出显示
|
|
||||||
- 标题、数字、补充描述分层明显
|
|
||||||
- 支持接口数据为空时展示 `0` 和空说明
|
|
||||||
|
|
||||||
### 6.5 最近文件模块
|
|
||||||
|
|
||||||
需展示:
|
|
||||||
|
|
||||||
- 模块标题:`最近文件`
|
|
||||||
- 最近文件列表,建议至少显示 3 条
|
|
||||||
- 每条信息至少包含:
|
|
||||||
- 文件名
|
|
||||||
- 文件大小
|
|
||||||
- 最近更新时间
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 点击文件项可跳转 `/files`,并定位到该文件
|
|
||||||
- 文件名超长时需截断并保留 tooltip 或完整展示方案
|
|
||||||
|
|
||||||
### 6.6 课程模块
|
|
||||||
|
|
||||||
模块标题:`今日 / 本周课程`
|
|
||||||
|
|
||||||
模块内包含:
|
|
||||||
|
|
||||||
- 分段切换:`今日` / `本周`
|
|
||||||
- 课程列表,建议显示:
|
|
||||||
- 时间段
|
|
||||||
- 课程名称
|
|
||||||
- 教室或地点
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 默认选中 `今日`
|
|
||||||
- 点击 `本周` 后刷新为本周课表摘要
|
|
||||||
- 切换过程不可造成卡片高度明显抖动
|
|
||||||
|
|
||||||
### 6.7 快捷操作模块
|
|
||||||
|
|
||||||
需提供 4 个快捷入口:
|
|
||||||
|
|
||||||
- 上传文件
|
|
||||||
- 新建文件夹
|
|
||||||
- 进入网盘
|
|
||||||
- 查询成绩
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 上传文件:打开上传弹窗或跳转文件页并打开上传面板
|
|
||||||
- 新建文件夹:打开新建文件夹表单
|
|
||||||
- 进入网盘:跳转 `/files`
|
|
||||||
- 查询成绩:跳转 `/school` 并聚焦成绩查询区域
|
|
||||||
|
|
||||||
### 6.8 存储空间模块
|
|
||||||
|
|
||||||
需展示:
|
|
||||||
|
|
||||||
- 模块标题:`存储空间`
|
|
||||||
- 已使用容量 / 总容量,如 `12.6 GB / 50 GB`
|
|
||||||
- 使用进度条
|
|
||||||
- 百分比数值,如 `25%`
|
|
||||||
|
|
||||||
实现要求:
|
|
||||||
|
|
||||||
- 进度条宽度与百分比联动
|
|
||||||
- 数值格式统一保留 1 位小数或按产品约定显示
|
|
||||||
|
|
||||||
### 6.9 账号信息模块
|
|
||||||
|
|
||||||
需展示:
|
|
||||||
|
|
||||||
- 模块标题:`账号信息`
|
|
||||||
- 用户名
|
|
||||||
- 邮箱
|
|
||||||
|
|
||||||
建议补充:
|
|
||||||
|
|
||||||
- 后续预留头像、绑定状态、退出登录入口
|
|
||||||
|
|
||||||
### 6.10 总览页验收标准
|
|
||||||
|
|
||||||
- 各卡片数据层级清晰,首屏即可理解
|
|
||||||
- 快捷操作能通往对应模块
|
|
||||||
- 时间、课表、文件、容量信息均支持动态数据渲染
|
|
||||||
- 页面在 1280px 以上布局稳定,在平板和移动端能正常堆叠
|
|
||||||
|
|
||||||
## 7. 网盘页需求
|
|
||||||
|
|
||||||
### 7.1 页面目标
|
|
||||||
|
|
||||||
提供个人网盘文件浏览、路径导航、详情预览和基础操作入口。
|
|
||||||
|
|
||||||
### 7.2 页面结构
|
|
||||||
|
|
||||||
网盘页采用三栏布局:
|
|
||||||
|
|
||||||
- 左侧目录导航栏
|
|
||||||
- 中间文件内容区
|
|
||||||
- 右侧详细信息预览栏
|
|
||||||
|
|
||||||
### 7.3 左侧目录导航栏
|
|
||||||
|
|
||||||
建议包括两组内容:
|
|
||||||
|
|
||||||
- 快速访问
|
|
||||||
- 桌面
|
|
||||||
- 下载
|
|
||||||
- 文档
|
|
||||||
- 图片
|
|
||||||
- 网盘目录
|
|
||||||
- 我的文件
|
|
||||||
- 课程资料
|
|
||||||
- 项目归档
|
|
||||||
- 收藏夹
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 点击目录项刷新中间内容区
|
|
||||||
- 当前目录项应有激活态
|
|
||||||
- 若目录层级增加,建议支持树形展开
|
|
||||||
|
|
||||||
### 7.4 中间文件内容区
|
|
||||||
|
|
||||||
应包含以下元素:
|
|
||||||
|
|
||||||
- 路径面包屑栏
|
|
||||||
- 视图切换控件:`列表` / `分栏` / `预览`
|
|
||||||
- 文件列表表头
|
|
||||||
- 文件列表内容
|
|
||||||
- 底部操作按钮:`新建`、`上传`
|
|
||||||
|
|
||||||
面包屑要求:
|
|
||||||
|
|
||||||
- 当前示例路径为:`网盘 > 我的文件 > 课程资料 > 软件工程`
|
|
||||||
- 每一级路径应可点击返回
|
|
||||||
|
|
||||||
文件列表字段要求:
|
|
||||||
|
|
||||||
| 列名 | 说明 |
|
|
||||||
| --- | --- |
|
|
||||||
| 名称 | 文件或文件夹名称 |
|
|
||||||
| 修改日期 | 最近更新时间 |
|
|
||||||
| 类型 | 文件类型或目录类型 |
|
|
||||||
| 大小 | 文件大小;文件夹可显示 `—` |
|
|
||||||
|
|
||||||
列表交互要求:
|
|
||||||
|
|
||||||
- 支持单行选中
|
|
||||||
- 支持文件夹进入下一级目录
|
|
||||||
- 支持当前选中项同步到右侧详情栏
|
|
||||||
- 当前选中行需有明显高亮
|
|
||||||
- 文件名过长时截断处理
|
|
||||||
|
|
||||||
建议补充能力:
|
|
||||||
|
|
||||||
- 双击打开文件
|
|
||||||
- 右键菜单
|
|
||||||
- 多选
|
|
||||||
- 排序
|
|
||||||
- 搜索
|
|
||||||
|
|
||||||
### 7.5 右侧详细信息预览栏
|
|
||||||
|
|
||||||
需展示当前选中文件的详细信息:
|
|
||||||
|
|
||||||
- 当前选择的文件名
|
|
||||||
- 文件路径
|
|
||||||
- 文件大小
|
|
||||||
- 上传时间
|
|
||||||
|
|
||||||
建议扩展字段:
|
|
||||||
|
|
||||||
- 文件类型图标
|
|
||||||
- 最近编辑人
|
|
||||||
- 下载次数
|
|
||||||
- 预览缩略图
|
|
||||||
|
|
||||||
### 7.6 网盘页操作要求
|
|
||||||
|
|
||||||
主操作:
|
|
||||||
|
|
||||||
- 上传
|
|
||||||
- 新建
|
|
||||||
|
|
||||||
交互说明:
|
|
||||||
|
|
||||||
- 上传:支持本地文件选择,建议支持拖拽上传
|
|
||||||
- 新建:默认创建文件夹,也可为后续扩展新建文档保留能力
|
|
||||||
- 操作成功后,文件列表与统计信息应刷新
|
|
||||||
|
|
||||||
### 7.7 网盘页状态要求
|
|
||||||
|
|
||||||
- 空目录:显示空状态文案和“上传文件”入口
|
|
||||||
- 加载中:文件表格骨架屏
|
|
||||||
- 上传中:显示上传进度
|
|
||||||
- 上传失败:显示失败原因并支持重试
|
|
||||||
|
|
||||||
### 7.8 网盘页验收标准
|
|
||||||
|
|
||||||
- 三栏布局信息职责明确
|
|
||||||
- 面包屑、目录树、列表选中、右侧详情联动正常
|
|
||||||
- 上传与新建入口位置明显,交互闭环完整
|
|
||||||
- 小屏情况下可退化为“目录 / 列表 / 详情”分步展示
|
|
||||||
|
|
||||||
## 8. 教务页需求
|
|
||||||
|
|
||||||
### 8.1 页面目标
|
|
||||||
|
|
||||||
提供统一教务查询入口,用于查看课表、成绩及历史学期数据摘要。
|
|
||||||
|
|
||||||
### 8.2 页面结构
|
|
||||||
|
|
||||||
页面包含以下主要区域:
|
|
||||||
|
|
||||||
- 教务查询卡片
|
|
||||||
- 数据摘要卡片
|
|
||||||
- 课表抽屉卡片
|
|
||||||
- 成绩热力图区域
|
|
||||||
|
|
||||||
### 8.3 教务查询卡片
|
|
||||||
|
|
||||||
应包含以下字段:
|
|
||||||
|
|
||||||
| 字段 | 示例 | 说明 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 学号 | `2023123456` | 查询账号 |
|
|
||||||
| 密码 | `••••••••` | 教务系统密码 |
|
|
||||||
| 学期 | `2025 秋` | 当前选择学期 |
|
|
||||||
|
|
||||||
按钮包括:
|
|
||||||
|
|
||||||
- 查询课表
|
|
||||||
- 查询成绩
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 学号、密码、学期为必填项
|
|
||||||
- 点击 `查询课表` 后刷新课表抽屉和摘要区对应信息
|
|
||||||
- 点击 `查询成绩` 后刷新成绩区域和摘要区对应信息
|
|
||||||
- 建议保留上次成功查询的账号与学期缓存
|
|
||||||
|
|
||||||
### 8.4 数据摘要卡片
|
|
||||||
|
|
||||||
需展示缓存或最近一次查询结果摘要:
|
|
||||||
|
|
||||||
- 当前缓存账号
|
|
||||||
- 已保存课表学期
|
|
||||||
- 已保存成绩学期列表
|
|
||||||
|
|
||||||
实现要求:
|
|
||||||
|
|
||||||
- 未查询时显示空态说明
|
|
||||||
- 查询成功后即时更新
|
|
||||||
|
|
||||||
### 8.5 课表抽屉卡片
|
|
||||||
|
|
||||||
模块标题:`课表抽屉`
|
|
||||||
|
|
||||||
展示形式:
|
|
||||||
|
|
||||||
- 按星期分组展示课程
|
|
||||||
- 每条课程至少包含:
|
|
||||||
- 上课时间
|
|
||||||
- 课程名称
|
|
||||||
- 教室
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 右侧有明显的抽屉把手视觉提示
|
|
||||||
- 建议支持展开 / 收起或横向滑出效果
|
|
||||||
- 抽屉在平板和移动端可切为底部弹层
|
|
||||||
|
|
||||||
### 8.6 成绩视图切换
|
|
||||||
|
|
||||||
查询卡片内存在分段切换:
|
|
||||||
|
|
||||||
- 课表
|
|
||||||
- 成绩
|
|
||||||
|
|
||||||
要求:
|
|
||||||
|
|
||||||
- 默认激活 `课表`
|
|
||||||
- 切换到 `成绩` 时,页面焦点应转向成绩区域
|
|
||||||
- 当前激活项需具备明显视觉反馈
|
|
||||||
|
|
||||||
### 8.7 成绩热力图区域
|
|
||||||
|
|
||||||
模块标题:`成绩热力图`
|
|
||||||
|
|
||||||
需展示多个学期的成绩分布示意,设计稿中包含:
|
|
||||||
|
|
||||||
- `2024 秋`
|
|
||||||
- `2025 春`
|
|
||||||
- `2025 秋`
|
|
||||||
|
|
||||||
实现要求:
|
|
||||||
|
|
||||||
- 每个学期形成独立列
|
|
||||||
- 每列包含多个课程成绩条
|
|
||||||
- 颜色深浅或透明度表示成绩高低
|
|
||||||
- 条形右侧或内部显示分数
|
|
||||||
|
|
||||||
建议补充能力:
|
|
||||||
|
|
||||||
- 悬浮提示课程名、学分、绩点
|
|
||||||
- 学期筛选
|
|
||||||
- 按成绩排序
|
|
||||||
|
|
||||||
### 8.8 教务页状态要求
|
|
||||||
|
|
||||||
- 未查询:显示引导说明
|
|
||||||
- 查询中:按钮 loading,结果区骨架屏
|
|
||||||
- 查询成功:更新课表、摘要、成绩
|
|
||||||
- 查询失败:展示错误原因和重试入口
|
|
||||||
|
|
||||||
### 8.9 教务页验收标准
|
|
||||||
|
|
||||||
- 查询表单、结果摘要、课表和成绩之间联动清晰
|
|
||||||
- 抽屉与热力图区域在不同状态下布局稳定
|
|
||||||
- 历史学期成绩能正确映射为视觉强弱差异
|
|
||||||
|
|
||||||
## 9. 游戏页需求
|
|
||||||
|
|
||||||
### 9.1 页面目标
|
|
||||||
|
|
||||||
作为轻量娱乐入口页,承载站内小游戏展示和启动入口。
|
|
||||||
|
|
||||||
### 9.2 页面结构
|
|
||||||
|
|
||||||
页面包含:
|
|
||||||
|
|
||||||
- 顶部导航
|
|
||||||
- 页面说明 Hero 区
|
|
||||||
- 分类切换
|
|
||||||
- 游戏卡片列表
|
|
||||||
|
|
||||||
### 9.3 Hero 区
|
|
||||||
|
|
||||||
需展示:
|
|
||||||
|
|
||||||
- 模块标题:`游戏入口`
|
|
||||||
- 一段说明文案,表达“保留轻量试玩与静态资源检查入口,维持与整站一致的毛玻璃语言”
|
|
||||||
|
|
||||||
### 9.4 分类切换
|
|
||||||
|
|
||||||
设计稿中包含:
|
|
||||||
|
|
||||||
- 精选
|
|
||||||
- 全部
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 默认选中 `精选`
|
|
||||||
- 点击后刷新卡片列表
|
|
||||||
- 若当前仅有少量游戏,`全部` 可与 `精选` 数据一致
|
|
||||||
|
|
||||||
### 9.5 游戏卡片
|
|
||||||
|
|
||||||
设计稿中至少包含两个游戏入口:
|
|
||||||
|
|
||||||
| 名称 | 描述 | 按钮文案 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| CAT | 简单的小猫升级游戏 | Launch |
|
|
||||||
| RACE | 赛车休闲小游戏 | Launch |
|
|
||||||
|
|
||||||
交互要求:
|
|
||||||
|
|
||||||
- 点击 `Launch` 后进入游戏详情页、游戏运行页或新窗口
|
|
||||||
- 游戏卡片需支持封面图扩展位
|
|
||||||
- 后续支持增加更多游戏时,卡片布局可扩展
|
|
||||||
|
|
||||||
### 9.6 游戏页验收标准
|
|
||||||
|
|
||||||
- 卡片入口清晰,用户能快速理解每个游戏内容
|
|
||||||
- 分类切换有效
|
|
||||||
- 启动按钮行为明确,不产生死链
|
|
||||||
|
|
||||||
## 10. 数据与接口需求建议
|
|
||||||
|
|
||||||
### 10.1 登录相关
|
|
||||||
|
|
||||||
- 登录接口:提交用户名和密码,返回用户信息与 token
|
|
||||||
- 获取当前登录用户接口:用于页面初始化恢复登录态
|
|
||||||
|
|
||||||
### 10.2 总览相关
|
|
||||||
|
|
||||||
- 获取总览统计接口
|
|
||||||
- 获取最近文件接口
|
|
||||||
- 获取今日 / 本周课表摘要接口
|
|
||||||
- 获取账号信息接口
|
|
||||||
- 获取存储容量接口
|
|
||||||
|
|
||||||
### 10.3 网盘相关
|
|
||||||
|
|
||||||
- 获取目录树接口
|
|
||||||
- 获取当前路径文件列表接口
|
|
||||||
- 获取文件详情接口
|
|
||||||
- 上传文件接口
|
|
||||||
- 新建文件夹接口
|
|
||||||
|
|
||||||
### 10.4 教务相关
|
|
||||||
|
|
||||||
- 查询课表接口
|
|
||||||
- 查询成绩接口
|
|
||||||
- 获取历史查询缓存接口
|
|
||||||
|
|
||||||
### 10.5 游戏相关
|
|
||||||
|
|
||||||
- 获取游戏列表接口
|
|
||||||
- 获取游戏分类接口
|
|
||||||
|
|
||||||
## 11. 前端实现建议
|
|
||||||
|
|
||||||
- 建议将顶部导航抽为全局公共组件
|
|
||||||
- 建议将卡片、按钮、分段切换、信息列表抽为复用组件
|
|
||||||
- 建议为每个页面单独维护数据请求与状态管理
|
|
||||||
- 建议所有动态时间、容量、数量、成绩统一做格式化封装
|
|
||||||
- 建议页面首屏背景光斑与毛玻璃效果使用纯 CSS 或轻量方案实现,避免过重图像资源
|
|
||||||
|
|
||||||
## 12. 测试验收清单
|
|
||||||
|
|
||||||
- 登录页表单校验、错误提示、提交跳转正常
|
|
||||||
- 顶部导航在 5 个页面间切换正常,当前态正确
|
|
||||||
- 总览页卡片数据渲染与快捷跳转正常
|
|
||||||
- 网盘页目录、路径、列表、详情联动正常
|
|
||||||
- 教务页查询、切换、热力图展示正常
|
|
||||||
- 游戏页分类切换和启动行为正常
|
|
||||||
- 页面在桌面、平板、移动端无明显布局错乱
|
|
||||||
- 页面无横向滚动,文本无明显遮挡
|
|
||||||
- 键盘可访问性与 focus 状态正常
|
|
||||||
|
|
||||||
## 13. 交付物建议
|
|
||||||
|
|
||||||
前端开发阶段建议同步产出以下内容:
|
|
||||||
|
|
||||||
- 页面路由结构
|
|
||||||
- 公共布局组件
|
|
||||||
- 各页面接口类型定义
|
|
||||||
- 空状态、错误状态、加载状态组件
|
|
||||||
- 基础 UI 规范说明文档
|
|
||||||
|
|
||||||
2697
草图/pencil-new.pen
2697
草图/pencil-new.pen
File diff suppressed because it is too large
Load Diff
182
需求文档.md
182
需求文档.md
@@ -1,182 +0,0 @@
|
|||||||
---
|
|
||||||
# 文件 1:Yoyuzh_Portal_需求文档.md
|
|
||||||
|
|
||||||
# Yoyuzh Personal Portal 后端需求文档
|
|
||||||
|
|
||||||
## 项目概述
|
|
||||||
该项目为 **yoyuzh.xyz** 的后端系统,提供用户身份认证、个人网盘功能以及重庆大学校园信息接口整合,供前端 Vue3 页面调用。
|
|
||||||
|
|
||||||
主要功能:
|
|
||||||
1. 用户身份认证与管理(注册、登录、JWT、密码加密)
|
|
||||||
2. 个人网盘(文件上传/下载/删除/目录管理/分页列表)
|
|
||||||
3. 重庆大学校园信息接口(课表、成绩)
|
|
||||||
4. RESTful API 风格,安全、可扩展
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 技术选型
|
|
||||||
| 模块 | 技术/框架 | 说明 |
|
|
||||||
|------------|---------------------------|--------------------------------|
|
|
||||||
| 后端框架 | Spring Boot 3.x | Java RESTful 后端快速开发 |
|
|
||||||
| 数据库 | MySQL / openGauss | 用户、文件、课程信息存储 |
|
|
||||||
| 安全 | Spring Security + JWT | 身份认证、接口权限控制 |
|
|
||||||
| 文件存储 | 本地文件系统 / 阿里云 OSS | 网盘文件存储 |
|
|
||||||
| 构建工具 | Maven | 依赖管理 |
|
|
||||||
| API 文档 | Swagger / Springdoc | 自动生成接口文档 |
|
|
||||||
| 日志 | SLF4J + Logback | 日志管理 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 功能模块
|
|
||||||
|
|
||||||
### 1. 用户身份认证
|
|
||||||
- 注册:`POST /api/auth/register`,加密密码存储,防止重复用户名/邮箱
|
|
||||||
- 登录:`POST /api/auth/login`,验证密码并生成 JWT
|
|
||||||
- JWT 验证:拦截需要权限接口,验证 Token,有效则注入用户信息
|
|
||||||
- 获取用户信息:`GET /api/user/profile`
|
|
||||||
|
|
||||||
### 2. 个人网盘
|
|
||||||
- 文件上传:`POST /api/files/upload`,文件流 + 路径
|
|
||||||
- 文件下载:`GET /api/files/download/{fileId}`
|
|
||||||
- 文件删除:`DELETE /api/files/{fileId}`
|
|
||||||
- 文件列表:`GET /api/files/list?path=&page=&size=`
|
|
||||||
- 目录管理:`POST /api/files/mkdir`
|
|
||||||
|
|
||||||
### 3. 重庆大学校园信息接口
|
|
||||||
- 课表查询:`GET /api/cqu/schedule`,学期/学号参数
|
|
||||||
- 成绩查询:`GET /api/cqu/grades`,学期/学号参数
|
|
||||||
- 实现:调用现有 API,转换统一 JSON 格式
|
|
||||||
|
|
||||||
### 4. 安全与权限
|
|
||||||
- 网盘接口需登录授权
|
|
||||||
- 学校信息接口可设置登录访问
|
|
||||||
- 文件操作需校验用户身份
|
|
||||||
|
|
||||||
### 5. 日志与异常
|
|
||||||
- SLF4J + Logback 日志
|
|
||||||
- 全局异常处理,统一 JSON 错误返回
|
|
||||||
- 错误码示例:
|
|
||||||
- 1000:未知错误
|
|
||||||
- 1001:用户未登录
|
|
||||||
- 1002:权限不足
|
|
||||||
- 1003:文件不存在
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 数据库设计
|
|
||||||
### 用户表 (user)
|
|
||||||
```
|
|
||||||
id PK
|
|
||||||
username VARCHAR
|
|
||||||
email VARCHAR
|
|
||||||
password_hash VARCHAR
|
|
||||||
created_at DATETIME
|
|
||||||
```
|
|
||||||
|
|
||||||
### 文件表 (file)
|
|
||||||
```
|
|
||||||
id PK
|
|
||||||
user_id FK -> user.id
|
|
||||||
filename VARCHAR
|
|
||||||
path VARCHAR
|
|
||||||
size BIGINT
|
|
||||||
created_at DATETIME
|
|
||||||
```
|
|
||||||
|
|
||||||
### 课程表 (course)
|
|
||||||
```
|
|
||||||
id PK
|
|
||||||
user_id FK -> user.id
|
|
||||||
course_name VARCHAR
|
|
||||||
teacher VARCHAR
|
|
||||||
classroom VARCHAR
|
|
||||||
day_of_week INT
|
|
||||||
start_time INT
|
|
||||||
end_time INT
|
|
||||||
```
|
|
||||||
|
|
||||||
### 成绩表 (grade)
|
|
||||||
```
|
|
||||||
id PK
|
|
||||||
user_id FK -> user.id
|
|
||||||
course_name VARCHAR
|
|
||||||
grade FLOAT
|
|
||||||
semester VARCHAR
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 项目结构
|
|
||||||
```
|
|
||||||
yoyuzh-portal-backend
|
|
||||||
│
|
|
||||||
├─ src/main/java/com/yoyuzh
|
|
||||||
│ ├─ auth # 用户注册/登录/JWT
|
|
||||||
│ ├─ files # 网盘管理
|
|
||||||
│ ├─ cqu # 校园信息 API
|
|
||||||
│ ├─ common # 全局异常处理/工具类
|
|
||||||
│ └─ config # Spring Security / JWT / Swagger 配置
|
|
||||||
│
|
|
||||||
├─ src/main/resources
|
|
||||||
│ ├─ application.yml # 数据库/OSS/JWT配置
|
|
||||||
│ └─ logback.xml # 日志配置
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 文件 2:Yoyuzh_Portal_实现细则.md
|
|
||||||
|
|
||||||
# Yoyuzh Personal Portal 后端实现细则
|
|
||||||
|
|
||||||
## 1. 用户认证细则
|
|
||||||
- 密码使用 BCrypt 加密存储
|
|
||||||
- JWT 有效期 1 天,可刷新
|
|
||||||
- 注册接口验证邮箱和用户名唯一性
|
|
||||||
- 登录接口返回 Token + 用户基础信息
|
|
||||||
- 所有需要权限接口通过 JWT Filter 校验
|
|
||||||
- 异常统一抛出,JSON 返回
|
|
||||||
|
|
||||||
## 2. 网盘实现细则
|
|
||||||
- 上传文件保存路径:`/storage/{userId}/{目录路径}/文件名`
|
|
||||||
- 文件大小限制:默认 50MB,可在配置文件调整
|
|
||||||
- 文件列表分页:前端请求 `page` 和 `size`
|
|
||||||
- 删除文件时先校验用户身份,确保只能删除自己上传的文件
|
|
||||||
- 支持创建多级目录,目录路径在数据库中记录
|
|
||||||
|
|
||||||
## 3. 重庆大学接口细则
|
|
||||||
- 调用现有 API 获取课表和成绩
|
|
||||||
- 统一 JSON 输出:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 0,
|
|
||||||
"msg": "success",
|
|
||||||
"data": [...]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- 若用户未登录或 Token 无效,可返回 1001 错误码
|
|
||||||
- 前端可通过学期参数过滤数据
|
|
||||||
|
|
||||||
## 4. 安全与权限细则
|
|
||||||
- Spring Security 配置:
|
|
||||||
- `/api/auth/**` 和 Swagger 接口无需认证
|
|
||||||
- `/api/files/**` 需要认证
|
|
||||||
- `/api/cqu/**` 可选认证
|
|
||||||
- JWT Token 通过 Authorization Header 传递:`Bearer {token}`
|
|
||||||
|
|
||||||
## 5. 日志与异常处理
|
|
||||||
- 所有接口调用记录 info 日志
|
|
||||||
- 异常统一在 `@ControllerAdvice` 中处理
|
|
||||||
- 返回 JSON 格式:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 1000,
|
|
||||||
"msg": "error message"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 6. 数据库细则
|
|
||||||
- 用户表:唯一索引 username、email
|
|
||||||
- 文件表:user_id + path + filename 组合唯一
|
|
||||||
- 课程表、成绩表与用户表关联,保证查询方便
|
|
||||||
- 建议为文件表、课程表添加创建时间索引,加快分页查询
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user