前言
不知不觉,这个系列已经做了4篇了。感谢大家对这个系列的支持!
你会发现,从第3篇开始,我们不再使用XP面板。这是因为我希望大家能从一步一步的调试中,体会到coding的乐趣。
随着信息技术的迅猛发展,学校的管理模式也在不断演变。传统的成绩单管理方式已经无法满足现代教育的需求,尤其是在数据存储、查询和分析方面。本文将详细介绍如何使用云服务器搭建一个功能齐全的学校成绩单系统,包括系统架构、技术选型、功能实现和界面优化等方面。
系统需求分析
在搭建学校成绩单系统之前,我们需要明确系统的基本需求:
功能需求
用户管理
学生注册与登录
教师与管理员账户管理
成绩管理
教师录入成绩
学生查看成绩
成绩统计与分析
课程管理
课程信息录入
课程与教师的关联
通知公告
发布学校通知
学生查看通知
数据备份与恢复
定期备份成绩数据
数据恢复功能
1.2 非功能需求
安全性
数据加密
权限控制
可扩展性
系统能够支持未来的功能扩展
用户体验
界面友好,操作简单
技术选型
为了实现以上需求,我们需要选择合适的技术栈。本期使用的技术选型:
前端
框架: Vue.js
UI组件库: Element UI
状态管理: Vuex
后端
框架: Flask
数据库: MySQL
ORM: SQLAlchemy
服务器部署
打开雨云官网,点击右上角的 登录/注册,按要求注册一个账号,优惠码记得填pyao
。
注册好后,选择 云服务器,选择 购买云服务器。
区域推荐香港四区,CPU Xeon®️ Gold,配置2核2G足够了。
购买后,先等个3分钟创建服务器,然后就可以开始部署了!
开始搭建
连接SSH
打开服务器管理面板,找到远程连接,然后按下Win
+R
打开运行框,输入cmd
回车。
然后输入:
ssh root@your_server_ip
输入密码后出现root@XXX:~#
就表示成功了!
安装必要软件
apt update
apt upgrade
reboot
reboot
后,SSH连接将会断开,过个3-5分钟重新连接回去就好了。
apt install python3-pip python3-dev nginx mysql-server
配置数据库
登录数据库
mysql -u root -p
创建数据库
CREATE DATABASE school_system;
创建用户并授权
CREATE USER "school_user"@"localhost" IDENTIFIED BY "your_password";
GRANT ALL PRIVILEGES ON school_system.* TO "school_user"@"localhost";
FLUSH PRIVILEGES;
后端开发
创建Flask项目
mkdir school_system
cd school_system
python3 -m venv venv
source venv/bin/activate
pip install Flask Flask-SQLAlchemy
如果最后一条命令不成功,就把pip
改为pip3
。
编写config.py
import os
class Config:
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://school_user:your_password@localhost/school_system"
SQLALCHEMY_TRACK_MODIFICATIONS = False
编写models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
grades = db.relationship("Grade", backref="student", lazy=True)
class Grade(db.Model):
id = db.Column(db.Integer, primary_key=True)
subject = db.Column(db.String(50), nullable=False)
score = db.Column(db.Float, nullable=False)
student_id = db.Column(db.Integer, db.ForeignKey("student.id"), nullable=False)
编写routes.py
from flask import Flask, request, jsonify
from models import db, Student, Grade
app = Flask(__name__)
app.config.from_object('config.Config')
db.init_app(app)
# 添加学生
@app.route('/add_student', methods=['POST'])
def add_student():
data = request.json
new_student = Student(name=data['name'])
db.session.add(new_student)
db.session.commit()
return jsonify({"message": "Student added successfully!"})
# 获取所有学生
@app.route('/students', methods=['GET'])
def get_students():
students = Student.query.all()
return jsonify([{"id": student.id, "name": student.name} for student in students])
# 修改学生信息
@app.route('/update_student/<int:student_id>', methods=['PUT'])
def update_student(student_id):
data = request.json
student = Student.query.get(student_id)
if student:
student.name = data['name']
db.session.commit()
return jsonify({"message": "Student updated successfully!"})
return jsonify({"message": "Student not found!"}), 404
# 删除学生
@app.route('/delete_student/<int:student_id>', methods=['DELETE'])
def delete_student(student_id):
student = Student.query.get(student_id)
if student:
db.session.delete(student)
db.session.commit()
return jsonify({"message": "Student deleted successfully!"})
return jsonify({"message": "Student not found!"}), 404
# 添加成绩
@app.route('/add_grade', methods=['POST'])
def add_grade():
data = request.json
new_grade = Grade(subject=data['subject'], score=data['score'], student_id=data['student_id'])
db.session.add(new_grade)
db.session.commit()
return jsonify({"message": "Grade added successfully!"})
# 修改成绩
@app.route('/update_grade/<int:grade_id>', methods=['PUT'])
def update_grade(grade_id):
data = request.json
grade = Grade.query.get(grade_id)
if grade:
grade.subject = data['subject']
grade.score = data['score']
db.session.commit()
return jsonify({"message": "Grade updated successfully!"})
return jsonify({"message": "Grade not found!"}), 404
# 删除成绩
@app.route('/delete_grade/<int:grade_id>', methods=['DELETE'])
def delete_grade(grade_id):
grade = Grade.query.get(grade_id)
if grade:
db.session.delete(grade)
db.session.commit()
return jsonify({"message": "Grade deleted successfully!"})
return jsonify({"message": "Grade not found!"}), 404
运行Flask应用
export FLASK_APP=app.py
flask run --host=0.0.0.0
前端开发
创建Vue项目
npm install -g @vue/cli
vue create school-frontend
安装Element UI
cd school-frontend
npm install element-ui
编写src/main.js
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
在src/views
下创建并修改Grades.vue
<template>
<div>
<h2>成绩管理</h2>
<el-input v-model="subject" placeholder="科目"></el-input>
<el-input v-model="score" type="number" placeholder="成绩"></el-input>
<el-select v-model="selectedStudentId" placeholder="选择学生">
<el-option
v-for="student in students"
:key="student.id"
:label="student.name"
:value="student.id">
</el-option>
</el-select>
<el-button @click="addGrade">添加成绩</el-button>
<el-table :data="grades" style="width: 100%">
<el-table-column prop="subject" label="科目"></el-table-column>
<el-table-column prop="score" label="成绩"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click="editGrade(scope.row)">修改</el-button>
<el-button @click="deleteGrade(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="dialogVisible">
<el-input v-model="editSubject" placeholder="科目"></el-input>
<el-input v-model="editScore" type="number" placeholder="成绩"></el-input>
<el-button @click="updateGrade">确认修改</el-button>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
subject: '',
score: '',
selectedStudentId: null,
grades: [],
students: [],
dialogVisible: false,
editGradeId: null,
editSubject: '',
editScore: ''
};
},
methods: {
fetchGrades() {
// 获取成绩列表
this.$http.get('/api/grades').then(response => {
this.grades = response.data;
});
},
fetchStudents() {
// 获取学生列表
this.$http.get('/api/students').then(response => {
this.students = response.data;
});
},
addGrade() {
if (!this.subject || !this.score || !this.selectedStudentId) {
this.$message.error('请填写所有字段');
return;
}
this.$http.post('/api/add_grade', {
subject: this.subject,
score: this.score,
student_id: this.selectedStudentId
}).then(response => {
this.$message.success(response.data.message);
this.fetchGrades();
});
},
editGrade(grade) {
this.editGradeId = grade.id;
this.editSubject = grade.subject;
this.editScore = grade.score;
this.dialogVisible = true;
},
updateGrade() {
this.$http.put(`/api/update_grade/${this.editGradeId}`, {
subject: this.editSubject,
score: this.editScore
}).then(response => {
this.$message.success(response.data.message);
this.fetchGrades();
this.dialogVisible = false;
});
},
deleteGrade(gradeId) {
this.$http.delete(`/api/delete_grade/${gradeId}`).then(response => {
this.$message.success(response.data.message);
this.fetchGrades();
});
}
},
mounted() {
this.fetchGrades();
this.fetchStudents();
}
};
</script>
创建并修改Students.vue
<template>
<div>
<h2>学生管理</h2>
<el-input v-model="studentName" placeholder="学生姓名"></el-input>
<el-button @click="addStudent">添加学生</el-button>
<el-table :data="students" style="width: 100%">
<el-table-column prop="name" label="学生姓名"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click="editStudent(scope.row)">修改</el-button>
<el-button @click="deleteStudent(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="dialogVisible">
<el-input v-model="editStudentName" placeholder="学生姓名"></el-input>
<el-button @click="updateStudent">确认修改</el-button>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
studentName: '',
students: [],
dialogVisible: false,
editStudentId: null,
editStudentName: ''
};
},
methods: {
fetchStudents() {
this.$http.get('/api/students').then(response => {
this.students = response.data;
});
},
addStudent() {
if (!this.studentName) {
this.$message.error('请填写学生姓名');
return;
}
this.$http.post('/api/add_student', { name: this.studentName }).then(response => {
this.$message.success(response.data.message);
this.fetchStudents();
});
},
editStudent(student) {
this.editStudentId = student.id;
this.editStudentName = student.name;
this.dialogVisible = true;
},
updateStudent() {
this.$http.put(`/api/update_student/${this.editStudentId}`, { name: this.editStudentName }).then(response => {
this.$message.success(response.data.message);
this.fetchStudents();
this.dialogVisible = false;
});
},
deleteStudent(studentId) {
this.$http.delete(`/api/delete_student/${studentId}`).then(response => {
this.$message.success(response.data.message);
this.fetchStudents();
});
}
},
mounted() {
this.fetchStudents();
}
};
</script>
建议
还有一些没实现的功能,大家可以参考:
响应式设计
使用 CSS Flexbox + Grid布局,使界面在不同设备上都能良好显示
主题定制
通过 Element UI 的主题定制功能,调整样式,使其符合学校的品牌形象。
交互
为按钮和输入添加过渡效果,让用户操作更加流畅。
部署与维护
部署后端
使用Gunicorn部署Flask
pip install gunicorn
gunicorn -w 4 app:app -b 0.0.0.0:8000
如果不成功,就把pip
改成pip3
。
配置Nginx反向代理
在/etc/nginx/sites/available/school_system
中添加配置:
server {
listen 80;
server_name your_domain_or_ip;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
重启Nginx
systemctl restart nginx
部署前端
npm run build
将dist
目录下的文件上传到Nginx的根目录。
在Nginx配置中添加:
location / {
root /path_to_your_frontend_dist;
try_files $uri $uri/ /index.html;
}
总结
通过以上步骤,我们成功搭建了一个功能齐全的学校成绩单系统。该系统不仅具备基本的成绩管理功能,还通过云服务器实现了高可用性和可扩展性。未来,我们可以根据需求继续扩展系统功能,例如添加数据分析模块、移动端支持等。
但限于篇幅,仍有一些功能没有实现,如没有限制访问,这就导致学生可以通过网页篡改自己的数据等。
祝你的搭建之路顺利!