|
@ -11,6 +11,8 @@
|
||||||
# production
|
# production
|
||||||
/build
|
/build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.env.local
|
.env.local
|
||||||
|
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
@ -14,7 +14,7 @@ function SendTest(){
|
||||||
|
|
||||||
const subject = async ()=>{
|
const subject = async ()=>{
|
||||||
try{
|
try{
|
||||||
const subject_src=await axios.post('http://127.0.0.1:5000/teacher/return_question',{
|
const subject_src=await axios.post('/api/teacher/return_question',{
|
||||||
teacher_ID})
|
teacher_ID})
|
||||||
SetChoiceQuestion(subject_src.data['选择'])
|
SetChoiceQuestion(subject_src.data['选择'])
|
||||||
SetCompletion(subject_src.data['填空'])
|
SetCompletion(subject_src.data['填空'])
|
||||||
|
@ -41,7 +41,7 @@ function SendTest(){
|
||||||
|
|
||||||
const click_1= async()=>{
|
const click_1= async()=>{
|
||||||
try {
|
try {
|
||||||
const select_class_src = await axios.post('http://127.0.0.1:5000/teacher/select_class', {
|
const select_class_src = await axios.post('/api/teacher/select_class', {
|
||||||
teacher_ID
|
teacher_ID
|
||||||
});
|
});
|
||||||
background.style.display='block'
|
background.style.display='block'
|
||||||
|
@ -119,7 +119,7 @@ function SendTest(){
|
||||||
// 发布按钮
|
// 发布按钮
|
||||||
const release= async()=>{
|
const release= async()=>{
|
||||||
try{
|
try{
|
||||||
const release_src=await axios.post('http://127.0.0.1:5000/teacher/accept_test',{
|
const release_src=await axios.post('/api/teacher/accept_test',{
|
||||||
teacher_ID,
|
teacher_ID,
|
||||||
ChoiceQuestionSet,//选择题
|
ChoiceQuestionSet,//选择题
|
||||||
CompletionQuestionSet,//填空题
|
CompletionQuestionSet,//填空题
|
||||||
|
@ -131,7 +131,7 @@ function SendTest(){
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
alert('发布成功')
|
alert('发布成功')
|
||||||
window.location.href='http://localhost:3000/teacher/managetest'
|
window.location.href='http://36.138.114.105:30294/teacher/managetest'
|
||||||
}catch{
|
}catch{
|
||||||
alert('发布失败')
|
alert('发布失败')
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ function SendTrain(){
|
||||||
|
|
||||||
const Train_question_func=async()=>{
|
const Train_question_func=async()=>{
|
||||||
try{
|
try{
|
||||||
const Train_question_src=await axios.post('http://127.0.0.1:5000/teacher/fetch_train_question')
|
const Train_question_src=await axios.post('/api/teacher/fetch_train_question')
|
||||||
SetTrainquestion(Train_question_src.data)
|
SetTrainquestion(Train_question_src.data)
|
||||||
}catch{
|
}catch{
|
||||||
alert('Train_question_func出错')
|
alert('Train_question_func出错')
|
||||||
|
@ -29,7 +29,7 @@ function SendTrain(){
|
||||||
|
|
||||||
const SeleactClass= async()=>{
|
const SeleactClass= async()=>{
|
||||||
try {
|
try {
|
||||||
const select_class_src = await axios.post('http://127.0.0.1:5000/teacher/select_class', {
|
const select_class_src = await axios.post('/api/teacher/select_class', {
|
||||||
teacher_ID
|
teacher_ID
|
||||||
});
|
});
|
||||||
SetClassData(select_class_src.data['Class']);
|
SetClassData(select_class_src.data['Class']);
|
||||||
|
@ -66,7 +66,7 @@ function SendTrain(){
|
||||||
//发送题目
|
//发送题目
|
||||||
const SendTrainTest=async ()=>{
|
const SendTrainTest=async ()=>{
|
||||||
try{
|
try{
|
||||||
const SendTrainSrc=await axios.post('http://127.0.0.1:5000/teacher/SendTrainTest',{
|
const SendTrainSrc=await axios.post('/api/teacher/SendTrainTest',{
|
||||||
TrainChoice,
|
TrainChoice,
|
||||||
TrainCompletion,
|
TrainCompletion,
|
||||||
TrainJudge,
|
TrainJudge,
|
||||||
|
|
|
@ -15,10 +15,10 @@ function TeacherPage() {
|
||||||
// const is_login = localStorage.getItem('islogin');
|
// const is_login = localStorage.getItem('islogin');
|
||||||
// if (!is_login) {
|
// if (!is_login) {
|
||||||
// alert('未登录');
|
// alert('未登录');
|
||||||
// window.location.href = 'http://localhost:3000/signin';
|
// window.location.href = 'http://36.138.114.105:30294/signin';
|
||||||
// } else {
|
// } else {
|
||||||
// if(teacher_ID.length===8){
|
// if(teacher_ID.length===8){
|
||||||
// window.location.href='http://localhost:3000'
|
// window.location.href='http://36.138.114.105:30294'
|
||||||
// return
|
// return
|
||||||
// }else{
|
// }else{
|
||||||
// console.log(teacher_ID);
|
// console.log(teacher_ID);
|
||||||
|
@ -35,7 +35,7 @@ function TeacherPage() {
|
||||||
//查找班级
|
//查找班级
|
||||||
const select_class = async () => {
|
const select_class = async () => {
|
||||||
try {
|
try {
|
||||||
const select_class_src = await axios.post('http://127.0.0.1:5000/teacher/select_class', {
|
const select_class_src = await axios.post('/api/teacher/select_class', {
|
||||||
teacher_ID
|
teacher_ID
|
||||||
});
|
});
|
||||||
setClassData(select_class_src.data['Class']);
|
setClassData(select_class_src.data['Class']);
|
||||||
|
|
|
@ -14,7 +14,7 @@ function TeacherPage() {
|
||||||
const [classdata,setClassData]=useState([])
|
const [classdata,setClassData]=useState([])
|
||||||
const class_succeed = async () => {
|
const class_succeed = async () => {
|
||||||
try{
|
try{
|
||||||
const class_scr=await axios.post('http://127.0.0.1:5000/teacher/find_student',{key})
|
const class_scr=await axios.post('/api/teacher/find_student',{key})
|
||||||
const class_data=class_scr.data
|
const class_data=class_scr.data
|
||||||
setClassData(class_data[1])
|
setClassData(class_data[1])
|
||||||
setisclick(true)
|
setisclick(true)
|
||||||
|
|
|
@ -18,7 +18,7 @@ function TeacherPage() {
|
||||||
|
|
||||||
const select_class = async () => {
|
const select_class = async () => {
|
||||||
try {
|
try {
|
||||||
const select_class_src = await axios.post('http://127.0.0.1:5000/teacher/select_class',{
|
const select_class_src = await axios.post('/api/teacher/select_class',{
|
||||||
teacher_ID
|
teacher_ID
|
||||||
});
|
});
|
||||||
setClassData(select_class_src.data['Class']);
|
setClassData(select_class_src.data['Class']);
|
||||||
|
@ -45,7 +45,7 @@ function TeacherPage() {
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
const change_class = async () => {
|
const change_class = async () => {
|
||||||
try {
|
try {
|
||||||
const change_class_src = await axios.post('http://127.0.0.1:5000/teacher/change_class',{
|
const change_class_src = await axios.post('/api/teacher/change_class',{
|
||||||
teacher_ID,
|
teacher_ID,
|
||||||
selectedValue,
|
selectedValue,
|
||||||
testID
|
testID
|
||||||
|
@ -74,7 +74,7 @@ function TeacherPage() {
|
||||||
const click_detailed= async()=>{
|
const click_detailed= async()=>{
|
||||||
//获取详细信息
|
//获取详细信息
|
||||||
try{
|
try{
|
||||||
const detaileddata_src=await axios.post('http://127.0.0.1:5000/teacher/detaileddata',{
|
const detaileddata_src=await axios.post('/api/teacher/detaileddata',{
|
||||||
testID,
|
testID,
|
||||||
selectedValue,
|
selectedValue,
|
||||||
teacher_ID
|
teacher_ID
|
||||||
|
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -15,7 +15,7 @@ function HeaderNav() {
|
||||||
localStorage.removeItem('islogin')
|
localStorage.removeItem('islogin')
|
||||||
// setisChecked(false)
|
// setisChecked(false)
|
||||||
alert('注销成功')
|
alert('注销成功')
|
||||||
window.location.href='http://localhost:3000/signin'
|
window.location.href='http://36.138.114.105:30294/signin'
|
||||||
};
|
};
|
||||||
|
|
||||||
const [isChecked,setisChecked]=useState(false)
|
const [isChecked,setisChecked]=useState(false)
|
||||||
|
|
|
@ -15,7 +15,7 @@ function HeaderNavTeacher() {
|
||||||
localStorage.removeItem('islogin')
|
localStorage.removeItem('islogin')
|
||||||
// setisChecked(false)
|
// setisChecked(false)
|
||||||
alert('注销成功')
|
alert('注销成功')
|
||||||
window.location.href='http://localhost:3000/signin'
|
window.location.href='http://36.138.114.105:30294/signin'
|
||||||
};
|
};
|
||||||
|
|
||||||
const [isChecked,setisChecked]=useState(false)
|
const [isChecked,setisChecked]=useState(false)
|
||||||
|
|
|
@ -5,18 +5,12 @@ import React,{ useEffect,useState } from 'react';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
//图表
|
//图表
|
||||||
import { Line } from 'react-chartjs-2';
|
import { Line } from 'react-chartjs-2';
|
||||||
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend } from 'chart.js';
|
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Ticks } from 'chart.js';
|
||||||
|
import { max, min } from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
function Home(){
|
function Home(){
|
||||||
const outlog=()=>{
|
|
||||||
localStorage.removeItem('islogin')
|
|
||||||
// setisChecked(false)
|
|
||||||
alert('注销成功')
|
|
||||||
window.location.href='http://localhost:3000/signin'
|
|
||||||
};
|
|
||||||
|
|
||||||
const [isChecked,setisChecked]=useState(false)
|
const [isChecked,setisChecked]=useState(false)
|
||||||
//判断是否登录
|
//判断是否登录
|
||||||
// useEffect(()=>{
|
// useEffect(()=>{
|
||||||
|
@ -45,7 +39,7 @@ function Home(){
|
||||||
const student_succeed_func = async () => {
|
const student_succeed_func = async () => {
|
||||||
const student_ID=localStorage.getItem('islogin')
|
const student_ID=localStorage.getItem('islogin')
|
||||||
try{
|
try{
|
||||||
const student_succeed_src=await axios.post('http://127.0.0.1:5000/student',{
|
const student_succeed_src=await axios.post('/api/student',{
|
||||||
student_ID
|
student_ID
|
||||||
});
|
});
|
||||||
//提取课程
|
//提取课程
|
||||||
|
@ -63,9 +57,10 @@ function Home(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// useEffect(()=>{
|
|
||||||
// student_succeed_func()
|
useEffect(()=>{
|
||||||
// },[])
|
student_succeed_func()
|
||||||
|
},[])
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(lesson.length>0){
|
if(lesson.length>0){
|
||||||
|
@ -83,10 +78,6 @@ function Home(){
|
||||||
}
|
}
|
||||||
},[lesson])
|
},[lesson])
|
||||||
|
|
||||||
const click=()=>{
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
//折线图
|
//折线图
|
||||||
// 创建一个状态来存储图表的数据
|
// 创建一个状态来存储图表的数据
|
||||||
const [chartData, setChartData] = useState({
|
const [chartData, setChartData] = useState({
|
||||||
|
@ -109,8 +100,7 @@ function Home(){
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: '总体成绩分析',
|
label: '总体成绩分析',
|
||||||
// data: [10, 20, 30, 40, 50,60,70,80,90,100],
|
data: [62, 79, 71, 49, 70],
|
||||||
data:data,
|
|
||||||
fill: false,
|
fill: false,
|
||||||
backgroundColor:'#fff',
|
backgroundColor:'#fff',
|
||||||
borderColor: 'rgb(75, 192, 192)',
|
borderColor: 'rgb(75, 192, 192)',
|
||||||
|
@ -125,6 +115,11 @@ function Home(){
|
||||||
scales: {
|
scales: {
|
||||||
y: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
|
min:0,
|
||||||
|
max:100,
|
||||||
|
ticks:{
|
||||||
|
stepSize:10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
|
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 9.5 KiB |
|
@ -19,7 +19,7 @@ function Exam(){
|
||||||
const [testdata,settestdata]=useState('')
|
const [testdata,settestdata]=useState('')
|
||||||
const test_func= async()=>{
|
const test_func= async()=>{
|
||||||
try{
|
try{
|
||||||
const test_src= await axios.post('http://127.0.0.1:5000/student/get_test',{student_ID})
|
const test_src= await axios.post('/api/student/get_test',{student_ID})
|
||||||
const test_data=test_src.data['data']
|
const test_data=test_src.data['data']
|
||||||
settestdata(test_data)
|
settestdata(test_data)
|
||||||
}catch(error){
|
}catch(error){
|
||||||
|
@ -111,9 +111,6 @@ function Exam(){
|
||||||
for(let i of item){
|
for(let i of item){
|
||||||
if(i[2]===completion_answer[sum]){
|
if(i[2]===completion_answer[sum]){
|
||||||
setscore(prevscore => prevscore + 2);
|
setscore(prevscore => prevscore + 2);
|
||||||
|
|
||||||
}else{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,16 +129,15 @@ function Exam(){
|
||||||
if(isMounted){
|
if(isMounted){
|
||||||
const score_func=async()=>{
|
const score_func=async()=>{
|
||||||
try{
|
try{
|
||||||
const score_entry_src=await axios.post('http://127.0.0.1:5000/student/score_entry',{
|
const score_entry_src=await axios.post('/api/student/score_entry',{
|
||||||
student_ID,
|
student_ID,
|
||||||
score,
|
score,
|
||||||
examId
|
examId
|
||||||
})
|
})
|
||||||
console.log('能不能发送');
|
|
||||||
}catch(error){
|
}catch(error){
|
||||||
alert(error)
|
alert(error)
|
||||||
}
|
}
|
||||||
window.location.href='http://localhost:3000/subject'
|
window.location.href='http://36.138.114.105:30294/subject'
|
||||||
}
|
}
|
||||||
score_func()
|
score_func()
|
||||||
}else{
|
}else{
|
||||||
|
|
|
@ -17,22 +17,21 @@ function SubjectPage(){
|
||||||
//根据学生ID获取他的考试卷子
|
//根据学生ID获取他的考试卷子
|
||||||
const test=async()=>{
|
const test=async()=>{
|
||||||
try{
|
try{
|
||||||
const test_src= await axios.post('http://127.0.0.1:5000/student/get_test',{student_ID})
|
const test_src= await axios.post('/api/student/get_test',{student_ID})
|
||||||
settestdata(test_src.data['data'])
|
settestdata(test_src.data['data'])
|
||||||
}catch(error){
|
}catch(error){
|
||||||
alert(error)
|
alert('test出错')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
test()
|
test()
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
|
|
||||||
const [EndTestList,setEndTestList]=useState([])
|
const [EndTestList,setEndTestList]=useState([])
|
||||||
//获取他已经做过的试卷
|
//获取他已经做过的试卷
|
||||||
const end_test=async()=>{
|
const end_test=async()=>{
|
||||||
try{
|
try{
|
||||||
const end_test_src=await axios.post('http://127.0.0.1:5000/student/get_end_student',{student_ID})
|
const end_test_src=await axios.post('/api/student/get_end_student',{student_ID})
|
||||||
const obj=end_test_src.data['result']
|
const obj=end_test_src.data['result']
|
||||||
setEndTestList(obj)
|
setEndTestList(obj)
|
||||||
}catch(error){
|
}catch(error){
|
||||||
|
@ -46,10 +45,6 @@ function SubjectPage(){
|
||||||
|
|
||||||
//过期试卷
|
//过期试卷
|
||||||
const [outtest,setouttest]=useState({})
|
const [outtest,setouttest]=useState({})
|
||||||
//测试按钮
|
|
||||||
const click = () => {
|
|
||||||
console.log(testdata);
|
|
||||||
};
|
|
||||||
//分过期试卷⬇
|
//分过期试卷⬇
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
let test_list= []
|
let test_list= []
|
||||||
|
@ -71,7 +66,7 @@ function SubjectPage(){
|
||||||
|
|
||||||
const find_result_func=async()=>{
|
const find_result_func=async()=>{
|
||||||
try{
|
try{
|
||||||
const find_result=await axios.post('http://127.0.0.1:5000/student/fetch_result',{
|
const find_result=await axios.post('/api/student/fetch_result',{
|
||||||
student_ID
|
student_ID
|
||||||
})
|
})
|
||||||
setresult(find_result.data['result'])
|
setresult(find_result.data['result'])
|
||||||
|
@ -97,8 +92,6 @@ function SubjectPage(){
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>}
|
</div>}
|
||||||
<button onClick={click}>测试按钮</button>
|
|
||||||
|
|
||||||
<h3>已结束或完成的试卷与练习</h3>
|
<h3>已结束或完成的试卷与练习</h3>
|
||||||
{ outtest&& result&&<div className='test-subject'>
|
{ outtest&& result&&<div className='test-subject'>
|
||||||
{Object.keys(outtest).map((key)=>{
|
{Object.keys(outtest).map((key)=>{
|
||||||
|
|
|
@ -83,19 +83,32 @@
|
||||||
|
|
||||||
/* 前进按钮 */
|
/* 前进按钮 */
|
||||||
.btn-back1{
|
.btn-back1{
|
||||||
height: 50px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 50px;
|
|
||||||
right: 80px;
|
|
||||||
padding: 0 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
/* border: 1px solid #000; */
|
|
||||||
box-shadow: 1px 2px 5px gray;
|
|
||||||
background-color: #efefef;
|
|
||||||
}
|
}
|
||||||
.btn-back1 p{
|
.btn-back1 p{
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.body-right1 table{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.optionBox{
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(110, 130, 130);
|
||||||
|
}
|
||||||
|
.body-right1 p{
|
||||||
|
margin: 0px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.optionBox label{
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.body-right1-comple{
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 10px; /* 设置行和列之间的间距 */
|
||||||
|
}
|
||||||
|
.body-right1-comple tr{
|
||||||
|
background-color: rgb(110, 130, 130);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,50 @@ import './Operation1.css'
|
||||||
import { Terminal } from "@xterm/xterm";
|
import { Terminal } from "@xterm/xterm";
|
||||||
import "@xterm/xterm/css/xterm.css"
|
import "@xterm/xterm/css/xterm.css"
|
||||||
import React,{ MouseEvent, useEffect, useRef, useState } from "react";
|
import React,{ MouseEvent, useEffect, useRef, useState } from "react";
|
||||||
|
import { useParams } from 'react-router';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import arrow from '../img/arrow.jpg'
|
import arrow from '../img/arrow.jpg'
|
||||||
import bottom from '../img/bottom.jpg'
|
import bottom from '../img/bottom.jpg'
|
||||||
import top from '../img/top.jpg'
|
import top from '../img/top.jpg'
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
function Operation1() {
|
function Operation1() {
|
||||||
|
const click=()=>{
|
||||||
|
console.log(score);
|
||||||
|
}
|
||||||
|
const clear=()=>{
|
||||||
|
localStorage.clear('choice_answers');
|
||||||
|
setchoice_answer({})
|
||||||
|
localStorage.clear('completion_answer')
|
||||||
|
setcompletion_answer({})
|
||||||
|
}
|
||||||
|
|
||||||
|
const { operateID } = useParams();
|
||||||
|
|
||||||
|
//获取试卷
|
||||||
|
const [TrainData,setTrainData]=useState()
|
||||||
|
const TrainDataFunc=async()=>{
|
||||||
|
try{
|
||||||
|
const TrainDataSrc=await axios.post('/api/student/TrainData',{
|
||||||
|
operateID
|
||||||
|
})
|
||||||
|
const returnData=TrainDataSrc.data
|
||||||
|
setTrainData(returnData)
|
||||||
|
}catch{
|
||||||
|
alert('TrainDataFunc出错')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
TrainDataFunc()
|
||||||
|
},[])
|
||||||
//倒计时
|
//倒计时
|
||||||
// const { OperationId } = useParams();
|
|
||||||
const [test_data, setTestData] = useState('');
|
const [test_data, setTestData] = useState('');
|
||||||
const [countdown, setCountdown] = useState(0);
|
const [countdown, setCountdown] = useState(0);
|
||||||
|
|
||||||
// 倒计时初始化
|
// 倒计时初始化
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const examDuration = 60 * 60; // 假设考试时长为1小时
|
const examDuration = 60 * 90; // 假设考试时长为1小时
|
||||||
setCountdown(examDuration);
|
setCountdown(examDuration);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -44,6 +73,88 @@ function Operation1() {
|
||||||
// 下拉菜单
|
// 下拉菜单
|
||||||
const [isSubjectDropdownOpen, setIsSubjectDropdownOpen] = useState(false);
|
const [isSubjectDropdownOpen, setIsSubjectDropdownOpen] = useState(false);
|
||||||
|
|
||||||
|
//创建答案字典,将用户填入的答案添加到答案字典
|
||||||
|
const [choice_answer,setchoice_answer]=useState({})
|
||||||
|
const [completion_answer,setcompletion_answer]=useState({})
|
||||||
|
const [judge_answer,setjudge_answer]=useState({})
|
||||||
|
|
||||||
|
//给选择题添加事件监听器
|
||||||
|
const handleOptionChange = (event) => {
|
||||||
|
const selectedValue = event.target.value;
|
||||||
|
const key = parseInt(event.target.name.replace('group', ''));
|
||||||
|
const updatedChoiceAnswer = { ...choice_answer, [key]: selectedValue };
|
||||||
|
setchoice_answer(updatedChoiceAnswer);
|
||||||
|
};
|
||||||
|
//填空题
|
||||||
|
const handleInputChange = (event) => {
|
||||||
|
const { name, value } = event.target;
|
||||||
|
setcompletion_answer({
|
||||||
|
...completion_answer,
|
||||||
|
[name]: value
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//判断题
|
||||||
|
const handleJudgeOption=(event)=>{
|
||||||
|
const judgeoption=event.target.value;
|
||||||
|
const key=parseInt(event.target.name.replace('judge',''))
|
||||||
|
const updatedJudgeAnswer={ ...judge_answer,[key]:judgeoption}
|
||||||
|
setjudge_answer(updatedJudgeAnswer)
|
||||||
|
}
|
||||||
|
|
||||||
|
//保存答案到 localStorage
|
||||||
|
const saveAnswers = () => {
|
||||||
|
localStorage.setItem('choice_answers', JSON.stringify(choice_answer));
|
||||||
|
localStorage.setItem('completion_answer', JSON.stringify(completion_answer));
|
||||||
|
localStorage.setItem('judge_answer',JSON.stringify(judge_answer))
|
||||||
|
};
|
||||||
|
|
||||||
|
// 在组件加载时从 localStorage 中恢复答案
|
||||||
|
useEffect(() => {
|
||||||
|
const storedChoiceAnswers = localStorage.getItem('choice_answers');
|
||||||
|
const storedCompleAnswers = localStorage.getItem('completion_answer');
|
||||||
|
const storedJudgeAnswers = localStorage.getItem('judge_answer')
|
||||||
|
if (storedChoiceAnswers) {
|
||||||
|
const parsedAnswers = JSON.parse(storedChoiceAnswers);
|
||||||
|
setchoice_answer(parsedAnswers);
|
||||||
|
}
|
||||||
|
if (storedCompleAnswers) {
|
||||||
|
const parsedAnswers = JSON.parse(storedCompleAnswers);
|
||||||
|
setcompletion_answer(parsedAnswers);
|
||||||
|
}
|
||||||
|
if(storedJudgeAnswers){
|
||||||
|
const parsedAnswers = JSON.parse(storedJudgeAnswers);
|
||||||
|
setjudge_answer(parsedAnswers);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
//不包含实训分数
|
||||||
|
const [score,setscore]=useState(0)
|
||||||
|
//提交按钮,或者下一页
|
||||||
|
const submit=()=>{
|
||||||
|
let CHO_sum=0;
|
||||||
|
let COM_sum=0;
|
||||||
|
let JUD_sum=0;
|
||||||
|
for(let item of TrainData['operateID'][0]){
|
||||||
|
if(item[0][6]===choice_answer[CHO_sum]){
|
||||||
|
setscore(prevscore=>prevscore+5)
|
||||||
|
}
|
||||||
|
CHO_sum++
|
||||||
|
}
|
||||||
|
for(let item of TrainData['operateID'][1]){
|
||||||
|
if (item[0][2]===completion_answer[COM_sum]) {
|
||||||
|
setscore(prevscore=>prevscore+5)
|
||||||
|
}
|
||||||
|
COM_sum++
|
||||||
|
}
|
||||||
|
for(let item of TrainData['operateID'][2]){
|
||||||
|
if (item[0][2]===judge_answer[JUD_sum]) {
|
||||||
|
setscore(prevscore=>prevscore+5)
|
||||||
|
}
|
||||||
|
JUD_sum++
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='nav-operation1'>
|
<div className='nav-operation1'>
|
||||||
|
@ -74,12 +185,60 @@ function Operation1() {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className='body-right1'>
|
<div className='body-right1'>
|
||||||
第一页(主观题)的右边页面
|
{TrainData && (
|
||||||
|
<table className='body-right1-choice'>
|
||||||
|
<p>选择题:</p>
|
||||||
|
<tbody>
|
||||||
|
{Object.keys(TrainData['operateID'][0]).map((key) => (
|
||||||
|
<tr key={key}>
|
||||||
|
<tr style={{fontSize:'18px'}}>{TrainData['operateID'][0][key][0][1]}</tr>
|
||||||
|
<div className='optionBox'>
|
||||||
|
<label><input type="radio" value={TrainData['operateID'][0][key][0][2]} checked={choice_answer[key] === TrainData['operateID'][0][key][0][2]} onChange={handleOptionChange} name={`group${key}`}/><span>A:{TrainData['operateID'][0][key][0][2]}</span></label>
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" value={TrainData['operateID'][0][key][0][3]} checked={choice_answer[key] === TrainData['operateID'][0][key][0][3]} onChange={handleOptionChange} name={`group${key}`}/><span>B:{TrainData['operateID'][0][key][0][3]}</span></label>
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" value={TrainData['operateID'][0][key][0][4]} checked={choice_answer[key] === TrainData['operateID'][0][key][0][4]} onChange={handleOptionChange} name={`group${key}`}/><span>C:{TrainData['operateID'][0][key][0][4]}</span></label>
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" value={TrainData['operateID'][0][key][0][5]} checked={choice_answer[key] === TrainData['operateID'][0][key][0][5]} onChange={handleOptionChange} name={`group${key}`}/><span>D:{TrainData['operateID'][0][key][0][5]}</span></label>
|
||||||
|
</div>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
{TrainData&&(
|
||||||
|
<table className='body-right1-comple'>
|
||||||
|
<tbody>
|
||||||
|
<p>填空题:</p>
|
||||||
|
{Object.keys(TrainData['operateID'][1]).map((key)=>(
|
||||||
|
<tr key={key}>{TrainData['operateID'][1][key][0][1]}
|
||||||
|
<br />
|
||||||
|
<span>请填入你的答案:</span>
|
||||||
|
<input type="text" onChange={handleInputChange} name={key} value={completion_answer[key]||''}/>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
{TrainData&&(
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<p>判断题:</p>
|
||||||
|
{Object.keys(TrainData['operateID'][2]).map((key)=>(
|
||||||
|
<tr key={key}>{TrainData['operateID'][2][key][0][1]}
|
||||||
|
<tr>
|
||||||
|
<label><input type="radio" name={`judge${key}`} checked={judge_answer[key] === 'true'} onChange={handleJudgeOption} value={true} />T</label>
|
||||||
|
<label><input type="radio" name={`judge${key}`} checked={judge_answer[key] === 'false'} onChange={handleJudgeOption} value={false} />F</label>
|
||||||
|
</tr>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
<button onClick={click}>测试</button><button onClick={clear}>清除测试</button><button onClick={submit}>假提交按钮</button>
|
||||||
|
<Link to={`/operation2/${operateID}`}><button onClick={saveAnswers}>下一页</button></Link>
|
||||||
</div>
|
</div>
|
||||||
<Link className='btn-back1' to={`/operation2/1`} style={{color:'#000',textDecoration:'none'}}>
|
|
||||||
<img src={arrow} alt="" width='40px' height='40px' />
|
|
||||||
<p>下一页</p>
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import './Operation2.css'
|
||||||
import { Terminal } from "@xterm/xterm";
|
import { Terminal } from "@xterm/xterm";
|
||||||
import "@xterm/xterm/css/xterm.css"
|
import "@xterm/xterm/css/xterm.css"
|
||||||
import React,{ MouseEvent, useEffect, useRef, useState } from "react";
|
import React,{ MouseEvent, useEffect, useRef, useState } from "react";
|
||||||
|
import { useParams } from 'react-router';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import arrow from '../img/arrow.jpg'
|
import arrow from '../img/arrow.jpg'
|
||||||
import arrow1 from '../img/left.jpg'
|
import arrow1 from '../img/left.jpg'
|
||||||
|
@ -9,6 +10,7 @@ import bottom from '../img/bottom.jpg'
|
||||||
import top from '../img/top.jpg'
|
import top from '../img/top.jpg'
|
||||||
|
|
||||||
function Operation2() {
|
function Operation2() {
|
||||||
|
const { operateID } = useParams();
|
||||||
//终端
|
//终端
|
||||||
const terminalObj = useRef(null);
|
const terminalObj = useRef(null);
|
||||||
let sock = null;
|
let sock = null;
|
||||||
|
@ -122,7 +124,7 @@ function Operation2() {
|
||||||
第二页(实训题)的右边页面
|
第二页(实训题)的右边页面
|
||||||
<div style={{width: "1430px",position:'absolute',right:'0'}} ref={terminalObj} onContextMenu={pasteContent}></div>
|
<div style={{width: "1430px",position:'absolute',right:'0'}} ref={terminalObj} onContextMenu={pasteContent}></div>
|
||||||
</div>
|
</div>
|
||||||
<Link className='btn-back2' to='/operation1/实训一:数据库的安装' style={{color:'#000',textDecoration:'none'}}>
|
<Link className='btn-back2' to={`/operation1/${operateID}`} style={{color:'#000',textDecoration:'none'}}>
|
||||||
<p>上一页</p>
|
<p>上一页</p>
|
||||||
<img src={arrow1} alt="" width='40px' height='40px' />
|
<img src={arrow1} alt="" width='40px' height='40px' />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -48,14 +48,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.exam-btn-training{
|
.exam-btn-training{
|
||||||
position: relative;
|
position: absolute;
|
||||||
margin-top: 50px;
|
margin-left: 260px;
|
||||||
margin-left: 250px;
|
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
|
margin-top: -10px;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
border: none;
|
border: none;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 3px 32px;
|
padding: 3px 26px;
|
||||||
background-color: rgba(175, 235, 230, 0.929);
|
background-color: rgba(175, 235, 230, 0.929);
|
||||||
color: #000;
|
color: #000;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -69,6 +69,13 @@
|
||||||
.exam-btn-training:active{
|
.exam-btn-training:active{
|
||||||
color:rgba(86, 117, 114, 0.929);
|
color:rgba(86, 117, 114, 0.929);
|
||||||
}
|
}
|
||||||
|
.bottomP{
|
||||||
|
color: red;
|
||||||
|
font-size: 20px;
|
||||||
|
margin-top: 350px;
|
||||||
|
margin-left: 70px;
|
||||||
|
letter-spacing: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,53 @@
|
||||||
import React,{ useState } from 'react';
|
import React,{ useState , useEffect} from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import '../Training/TrainingPage.css'
|
import '../Training/TrainingPage.css'
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
|
||||||
const list3=[
|
|
||||||
{'train':'实训一:数据库的安装',id:'1'},
|
|
||||||
{'train':'实训二:web前端开发和数据库的结合',id:'2'}
|
|
||||||
]
|
|
||||||
|
|
||||||
const list4=[
|
const list4=[
|
||||||
{'train':'实训3:待定',id:'3'},
|
{'train':'实训3:待定',id:'3'},
|
||||||
{'train':'实训4:待定',id:'4'}
|
{'train':'实训4:待定',id:'4'}
|
||||||
]
|
]
|
||||||
// 首页 学习分析
|
// 首页 学习分析
|
||||||
function SubjectPage(){
|
function SubjectPage(){
|
||||||
|
const student_ID=localStorage.getItem('islogin')
|
||||||
|
const [title,setTitle]=useState()
|
||||||
|
// 获取实训标题
|
||||||
|
const FetchTrainFunc=async()=>{
|
||||||
|
try{
|
||||||
|
const FetchTrainSrc=await axios.post('api/student/FetchTrainTitle',{
|
||||||
|
student_ID
|
||||||
|
})
|
||||||
|
setTitle(FetchTrainSrc.data['title'])
|
||||||
|
}catch{
|
||||||
|
alert('FetchTrainFunc出错')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
FetchTrainFunc()
|
||||||
|
},[])
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="body-right-training">
|
<div className="body-right-training">
|
||||||
<h3>未完成练习</h3>
|
<h3>未完成实训项目</h3>
|
||||||
<div className='test-training'>
|
{title&&<div className='test-training'>
|
||||||
{list3.map((item) =>(
|
{Object.keys(title).map((key)=>(
|
||||||
<div className='test-box-training'key={item.id}>
|
<div className='test-box-training' key={key}>
|
||||||
<p>{item.train}</p>
|
<p>实训:{eval(title[key][0][11])}</p>
|
||||||
<span>发布者:陈老师</span>
|
<span>发布者:陈老师</span>
|
||||||
<Link to={`/operation1/${item.train}`} className="exam-btn-training">
|
<div>发布时间:{title[key][0][5]}</div>
|
||||||
|
<div>截至时间:{title[key][0][6]}</div>
|
||||||
|
<Link to={`/operation1/${title[key][0][10]}`} className="exam-btn-training">
|
||||||
开始实训
|
开始实训
|
||||||
</Link>
|
</Link>
|
||||||
</div>))}
|
|
||||||
</div>
|
|
||||||
<h3>已完成练习</h3>
|
|
||||||
<div className='test-training'>
|
|
||||||
{list4.map((item) => (
|
|
||||||
<div className='test-box-training'key={item.id}>
|
|
||||||
<p>{item.train}</p>
|
|
||||||
<div>
|
|
||||||
{item.title}
|
|
||||||
</div>
|
|
||||||
</div>))}
|
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
|
</div>}
|
||||||
|
<button onClick={()=>{
|
||||||
|
console.log(title[0][0][11]);
|
||||||
|
}}></button>
|
||||||
|
<p className='bottomP'>提醒:请及时完成实训内容!!!</p>
|
||||||
</div>
|
</div>
|
||||||
)};
|
)};
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 11 KiB |
|
@ -62,7 +62,7 @@ import axios from 'axios';
|
||||||
alert('学号错误')
|
alert('学号错误')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const register_func=await axios.post('http://127.0.0.1:5000/register',{
|
const register_func=await axios.post('/api/register',{
|
||||||
name,
|
name,
|
||||||
ID,
|
ID,
|
||||||
password,
|
password,
|
||||||
|
|
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 205 KiB |
|
@ -12,7 +12,7 @@ function SignInPage(){
|
||||||
|
|
||||||
const login = async () => {
|
const login = async () => {
|
||||||
try {
|
try {
|
||||||
const login_data = await axios.post('http://127.0.0.1:5000/login', {
|
const login_data = await axios.post('/api/login', {
|
||||||
ID,
|
ID,
|
||||||
password
|
password
|
||||||
});
|
});
|
||||||
|
@ -21,11 +21,11 @@ function SignInPage(){
|
||||||
if (data.result === '登录成功' && data.user==='user'){
|
if (data.result === '登录成功' && data.user==='user'){
|
||||||
localStorage.setItem('islogin',ID)
|
localStorage.setItem('islogin',ID)
|
||||||
alert('用户登录成功')
|
alert('用户登录成功')
|
||||||
window.location.href='http://localhost:3000'//后期改成学生页面
|
window.location.href='http://36.138.114.105:30294'//后期改成学生页面
|
||||||
}else if(data.result==='登录成功'&&data.user==='teacher'){
|
}else if(data.result==='登录成功'&&data.user==='teacher'){
|
||||||
localStorage.setItem('islogin',ID)
|
localStorage.setItem('islogin',ID)
|
||||||
alert('教师登录成功')
|
alert('教师登录成功')
|
||||||
window.location.href='http://localhost:3000/teacher'//后期改成老师页面
|
window.location.href='http://36.138.114.105:30294/teacher'//后期改成老师页面
|
||||||
}else{
|
}else{
|
||||||
alert('账号或密码错误')
|
alert('账号或密码错误')
|
||||||
setID('')
|
setID('')
|
||||||
|
|
Before Width: | Height: | Size: 304 KiB After Width: | Height: | Size: 304 KiB |
|
@ -21,7 +21,7 @@ import ClassID from '../TeacherPages/classlistpages/classId';
|
||||||
import ManageTest from '../TeacherPages/teachermanagetest/ManageTest';
|
import ManageTest from '../TeacherPages/teachermanagetest/ManageTest';
|
||||||
import SendTest from '../TeacherPages/SendTest/SendTest';
|
import SendTest from '../TeacherPages/SendTest/SendTest';
|
||||||
import Marking from '../TeacherPages/MarkingPages/Marking';
|
import Marking from '../TeacherPages/MarkingPages/Marking';
|
||||||
import TrainManage from '../TeacherPages/SendTest/trainmanage';
|
import SendTrain from '../TeacherPages/SendTrain/SendTrain';
|
||||||
|
|
||||||
// 定义一个组件来包裹除了特定页面(exam)外的所有页面使其有导航
|
// 定义一个组件来包裹除了特定页面(exam)外的所有页面使其有导航
|
||||||
const MainLayout = ({ headerNav:HeaderNav }) => {
|
const MainLayout = ({ headerNav:HeaderNav }) => {
|
||||||
|
@ -54,7 +54,7 @@ function App() {
|
||||||
<Route path="/teacher" element={<MainLayout headerNav={HeaderNavTeacher} />}>
|
<Route path="/teacher" element={<MainLayout headerNav={HeaderNavTeacher} />}>
|
||||||
<Route index element={<TeacherPage/>} />
|
<Route index element={<TeacherPage/>} />
|
||||||
<Route path='managetest' element={<ManageTest />}/>
|
<Route path='managetest' element={<ManageTest />}/>
|
||||||
<Route path='managetest/:ClassID' element={<ManageTest />}/>
|
{/* <Route path='managetest/:ClassID' element={<ManageTest />}/> */}
|
||||||
<Route path="classID/:key" element={<ClassID />} />
|
<Route path="classID/:key" element={<ClassID />} />
|
||||||
<Route path='mark' element={<Marking/>}/>
|
<Route path='mark' element={<Marking/>}/>
|
||||||
<Route path='trainmanage' element={<TrainManage/>}/>
|
<Route path='trainmanage' element={<TrainManage/>}/>
|
||||||
|
@ -71,8 +71,7 @@ function App() {
|
||||||
<Route path='/teacher/sendtest' element={<SendTest />}/>
|
<Route path='/teacher/sendtest' element={<SendTest />}/>
|
||||||
<Route path='operation1/:operateID' element={<Operation1/>}/>
|
<Route path='operation1/:operateID' element={<Operation1/>}/>
|
||||||
<Route path='operation2/:operateID' element={<Operation2/>}/>
|
<Route path='operation2/:operateID' element={<Operation2/>}/>
|
||||||
|
<Route path='teacher/SendTrain' element={<SendTrain/>}/>
|
||||||
|
|
||||||
{/* 独立的顶级路由,如登录页面,也不包含HeaderNav */}
|
{/* 独立的顶级路由,如登录页面,也不包含HeaderNav */}
|
||||||
{/* 登录页面 */}
|
{/* 登录页面 */}
|
||||||
<Route path="signin" element={<SignInPage />} />
|
<Route path="signin" element={<SignInPage />} />
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
|
||||||
|
module.exports = function(app) {
|
||||||
|
app.use(
|
||||||
|
'/api', // 如果请求路径匹配'/api',则进行代理
|
||||||
|
createProxyMiddleware({
|
||||||
|
target: 'http://localhost:5000', // 目标后端服务地址
|
||||||
|
changeOrigin: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,3 +1,51 @@
|
||||||
docker compose build
|
#!/bin/bash
|
||||||
docker compose build build-dmpython
|
|
||||||
docker compose build build-frontend
|
# 获取当前文件夹名字
|
||||||
|
current_dir=$(basename "$PWD")
|
||||||
|
|
||||||
|
# 确保有稳定的网络环境
|
||||||
|
ensure_network() {
|
||||||
|
read -p "请确保有稳定的网络环境[Y/N] " confirm
|
||||||
|
if [[ ! $confirm =~ ^[yY]([eE][sS])?$ ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 打包镜像
|
||||||
|
build_image() {
|
||||||
|
local service_name=$1
|
||||||
|
echo "打包${service_name}镜像"
|
||||||
|
docker compose build "$service_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 推送镜像
|
||||||
|
push_image() {
|
||||||
|
read -p "是否要推送到《达梦启元云原生大数据平台》? [Y/N] " confirm
|
||||||
|
if [[ $confirm =~ ^[yY]([eE][sS])?$ ]]; then
|
||||||
|
echo "tag"
|
||||||
|
docker tag "${current_dir}-flask-app" 36.138.114.105:31000/cnsof50011836/flask-app
|
||||||
|
echo "pushing"
|
||||||
|
docker push 36.138.114.105:31000/cnsof50011836/flask-app
|
||||||
|
echo "pushed"
|
||||||
|
else
|
||||||
|
echo "用户选择不推送镜像"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 主流程
|
||||||
|
main() {
|
||||||
|
echo "打包中"
|
||||||
|
ensure_network
|
||||||
|
|
||||||
|
build_image base
|
||||||
|
build_image base-dm
|
||||||
|
build_image build-dmpython
|
||||||
|
build_image build-frontend
|
||||||
|
build_image flask-app
|
||||||
|
|
||||||
|
push_image
|
||||||
|
|
||||||
|
echo "脚本结束"
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
|
@ -1,8 +1,14 @@
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
base:
|
||||||
|
build: ./docker/base
|
||||||
|
image: base
|
||||||
|
|
||||||
base-dm:
|
base-dm:
|
||||||
build: ./docker/base-dm
|
build: ./docker/base-dm
|
||||||
image: base-dm
|
image: base-dm
|
||||||
|
depends_on:
|
||||||
|
- base
|
||||||
|
|
||||||
build-dmpython:
|
build-dmpython:
|
||||||
build: ./docker/build-dmpython
|
build: ./docker/build-dmpython
|
||||||
|
@ -28,20 +34,3 @@ services:
|
||||||
retries: 3
|
retries: 3
|
||||||
command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app
|
command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app
|
||||||
|
|
||||||
nginx-proxy:
|
|
||||||
build: ./docker/nginx
|
|
||||||
restart: always
|
|
||||||
volumes:
|
|
||||||
- ./docker/nginx/default.conf:/tmp/default.conf
|
|
||||||
environment:
|
|
||||||
- FLASK_SERVER_ADDR=flask-app:8000
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
depends_on:
|
|
||||||
- flask-app
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "curl --silent --fail localhost:80/health-check || exit 1"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
command: /app/start.sh
|
|
||||||
|
|
|
@ -1,31 +1,11 @@
|
||||||
FROM ubuntu
|
FROM base
|
||||||
# apt安装时,防止卡死在交互界面
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
ENV LANG=zh_CN.UTF-8
|
|
||||||
ENV LC_ALL=zh_CN.UTF-8
|
|
||||||
# 基础软件安装
|
|
||||||
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list \
|
|
||||||
&& apt-get -y update && apt-get -y upgrade \
|
|
||||||
&& apt-get install -y python3.10-venv libssl-dev sudo vim python3-pip ssh wget unzip p7zip* language-pack-zh-hans language-selector-common locales locales-all \
|
|
||||||
# 设置中文环境
|
|
||||||
&& apt install -y $(check-language-support) \
|
|
||||||
&& echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \
|
|
||||||
&& sudo /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \
|
|
||||||
&& locale-gen \
|
|
||||||
# 添加用户
|
# 添加用户
|
||||||
&& useradd -m -s /bin/bash dmdba \
|
RUN useradd -m -s /bin/bash dmdba \
|
||||||
# 修改用户密码
|
# 修改用户密码
|
||||||
&& echo "dmdba:123456" | chpasswd \
|
&& echo "dmdba:123456" | chpasswd
|
||||||
&& pip config set global.index-url https://mirrors.bfsu.edu.cn/pypi/web/simple \
|
|
||||||
&& echo "**** clean up ****" && \
|
|
||||||
apt-get clean && \
|
|
||||||
rm -rf \
|
|
||||||
/config/* \
|
|
||||||
/tmp/* \
|
|
||||||
/var/lib/apt/lists/* \
|
|
||||||
/var/tmp/*
|
|
||||||
# 传入安装包并解压
|
|
||||||
WORKDIR /home/dmdba
|
WORKDIR /home/dmdba
|
||||||
|
|
||||||
|
# 传入安装包并解压
|
||||||
RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip
|
RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip
|
||||||
RUN unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
RUN unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||||
&& chown -R dmdba:dmdba /home/dmdba \
|
&& chown -R dmdba:dmdba /home/dmdba \
|
||||||
|
@ -33,3 +13,4 @@ RUN unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||||
&& 7z x dm8_20240408_x86_rh7_64.iso \
|
&& 7z x dm8_20240408_x86_rh7_64.iso \
|
||||||
&& rm -f dm8_20240408_x86_rh7_64.iso \
|
&& rm -f dm8_20240408_x86_rh7_64.iso \
|
||||||
&& chmod +x DMInstall.bin
|
&& chmod +x DMInstall.bin
|
||||||
|
USER dmdba
|
|
@ -0,0 +1,22 @@
|
||||||
|
FROM ubuntu
|
||||||
|
# apt安装时,防止卡死在交互界面
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
ENV LANG=zh_CN.UTF-8
|
||||||
|
ENV LC_ALL=zh_CN.UTF-8
|
||||||
|
# 基础软件安装
|
||||||
|
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list \
|
||||||
|
&& apt-get -y update && apt-get -y upgrade \
|
||||||
|
&& apt-get install -y python3.10-venv libssl-dev sudo vim python3-pip ssh wget unzip p7zip* language-pack-zh-hans language-selector-common locales locales-all \
|
||||||
|
# 设置中文环境
|
||||||
|
&& apt install -y $(check-language-support) \
|
||||||
|
&& echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \
|
||||||
|
&& sudo /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \
|
||||||
|
&& locale-gen \
|
||||||
|
&& pip config set global.index-url https://mirrors.bfsu.edu.cn/pypi/web/simple \
|
||||||
|
&& echo "**** clean up ****" && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf \
|
||||||
|
/config/* \
|
||||||
|
/tmp/* \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/var/tmp/*
|
|
@ -115,7 +115,7 @@
|
||||||
</DB_PARAMS>
|
</DB_PARAMS>
|
||||||
|
|
||||||
<!--是否创建数据库实例的服务,取值范围: Y/N y/n,不允许为空,不初始化数据库将忽略此节点。非root用户不能创建数据库服务。 -->
|
<!--是否创建数据库实例的服务,取值范围: Y/N y/n,不允许为空,不初始化数据库将忽略此节点。非root用户不能创建数据库服务。 -->
|
||||||
<CREATE_DB_SERVICE>Y</CREATE_DB_SERVICE>
|
<CREATE_DB_SERVICE>N</CREATE_DB_SERVICE>
|
||||||
|
|
||||||
<!--是否启动数据库,取值范围: Y/N y/n,不允许为空,不创建数据库服务将忽略此节点。 -->
|
<!--是否启动数据库,取值范围: Y/N y/n,不允许为空,不创建数据库服务将忽略此节点。 -->
|
||||||
<STARTUP_DB_SERVICE>N</STARTUP_DB_SERVICE>
|
<STARTUP_DB_SERVICE>N</STARTUP_DB_SERVICE>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
FROM base-dm
|
FROM base
|
||||||
|
|
||||||
# 升级pip
|
# 升级pip
|
||||||
RUN pip install --upgrade pip
|
RUN pip install --upgrade pip
|
||||||
|
|
||||||
# 创建一个用户运行flask
|
# 创建一个用户运行flask
|
||||||
RUN adduser flask
|
RUN adduser flask && \
|
||||||
RUN chown -R flask:flask /home/flask
|
chown -R flask:flask /home/flask && \
|
||||||
RUN mkdir -p /var/log/flask-app && touch /var/log/flask-app/flask-app.err.log && touch /var/log/flask-app/flask-app.out.log
|
mkdir -p /var/log/flask-app && touch /var/log/flask-app/flask-app.err.log && touch /var/log/flask-app/flask-app.out.log && \
|
||||||
RUN chown -R flask:flask /var/log/flask-app
|
chown -R flask:flask /var/log/flask-app
|
||||||
WORKDIR /home/flask
|
WORKDIR /home/flask
|
||||||
USER flask
|
USER flask
|
||||||
|
|
||||||
|
@ -16,18 +16,18 @@ COPY --chown=flask:flask . .
|
||||||
|
|
||||||
# venv
|
# venv
|
||||||
ENV VIRTUAL_ENV=/home/flask/venv
|
ENV VIRTUAL_ENV=/home/flask/venv
|
||||||
|
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||||
|
|
||||||
# 安装包
|
# 安装包
|
||||||
RUN python3 -m venv "$VIRTUAL_ENV"
|
|
||||||
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
|
||||||
RUN export FLASK_APP=main.py
|
|
||||||
COPY --from=build-dmpython --chown=flask:flask /home/dmdba/build_artifacts/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl .
|
COPY --from=build-dmpython --chown=flask:flask /home/dmdba/build_artifacts/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl .
|
||||||
|
RUN python3 -m venv "$VIRTUAL_ENV" && \
|
||||||
|
export FLASK_APP=app.py && \
|
||||||
|
pip3 install dmPython-2.5.5-cp310-cp310-linux_x86_64.whl && rm dmPython-2.5.5-cp310-cp310-linux_x86_64.whl && \
|
||||||
|
MAKEFLAGS="-j$(nproc)" pip install -r requirements.txt
|
||||||
COPY --from=build-dmpython /home/dmdba/build_artifacts/libdmdpi.so /usr/lib/
|
COPY --from=build-dmpython /home/dmdba/build_artifacts/libdmdpi.so /usr/lib/
|
||||||
COPY --from=build-frontend /usr/src/app/build/ /home/flask/public/
|
COPY --from=build-frontend /usr/src/app/build/ /home/flask/public/
|
||||||
RUN pip3 install dmPython-2.5.5-cp310-cp310-linux_x86_64.whl && rm dmPython-2.5.5-cp310-cp310-linux_x86_64.whl
|
|
||||||
RUN MAKEFLAGS="-j$(nproc)" pip install -r requirements.txt
|
|
||||||
USER root
|
|
||||||
# 暴露端口
|
# 暴露端口
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
CMD ["python", "main.py"]
|
CMD ["gunicorn", "-w", "3", "-t", "60", "-b", "0.0.0.0:8000", "app:app"]
|
|
@ -8,7 +8,7 @@ CORS(app, resources={r"/*": {"origins": "*"}})
|
||||||
app.config['SECRET_KEY'] = '350625'
|
app.config['SECRET_KEY'] = '350625'
|
||||||
|
|
||||||
|
|
||||||
@app.route('/student', methods=['POST']) # 检测历史是否登录过,登录则直接进入index,反之则进去login界面
|
@app.route('/api/student', methods=['POST']) # 检测历史是否登录过,登录则直接进入index,反之则进去login界面
|
||||||
def student(): # 判断是否已经登录
|
def student(): # 判断是否已经登录
|
||||||
ID_data = request.json
|
ID_data = request.json
|
||||||
ID = ID_data['student_ID']
|
ID = ID_data['student_ID']
|
||||||
|
@ -17,13 +17,11 @@ def student(): # 判断是否已经登录
|
||||||
return jsonify({'student_succeed': student_succeed, 'student_lesson': student_lesson})
|
return jsonify({'student_succeed': student_succeed, 'student_lesson': student_lesson})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/login', methods=['POST']) # 登录功能
|
@app.route('/api/login', methods=['POST']) # 登录功能
|
||||||
def login():
|
def login():
|
||||||
login_data = request.json # 获取前端发送过来的数据
|
login_data = request.json # 获取前端发送过来的数据
|
||||||
ID = login_data['ID'] # 解析数据
|
ID = login_data['ID'] # 解析数据
|
||||||
password = login_data['password']
|
password = login_data['password']
|
||||||
print(ID)
|
|
||||||
print(password)
|
|
||||||
if len(ID) == 8: # 根据长度判断,长度为十则是学生
|
if len(ID) == 8: # 根据长度判断,长度为十则是学生
|
||||||
try:
|
try:
|
||||||
en_password, password = student_login_func(ID, password)
|
en_password, password = student_login_func(ID, password)
|
||||||
|
@ -65,7 +63,7 @@ def login():
|
||||||
|
|
||||||
# postman
|
# postman
|
||||||
|
|
||||||
@app.route('/logout', methods=['POST']) # 退出登录功能
|
@app.route('/api/logout', methods=['POST']) # 退出登录功能
|
||||||
def logout(): # 退出登录
|
def logout(): # 退出登录
|
||||||
ID = session['id']
|
ID = session['id']
|
||||||
print(ID)
|
print(ID)
|
||||||
|
@ -73,7 +71,7 @@ def logout(): # 退出登录
|
||||||
return jsonify({'result': '注销成功'})
|
return jsonify({'result': '注销成功'})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/register', methods=['POST']) # 注册功能实现
|
@app.route('/api/register', methods=['POST']) # 注册功能实现
|
||||||
def register():
|
def register():
|
||||||
register_data = request.json # 获取前端发送过来的数据
|
register_data = request.json # 获取前端发送过来的数据
|
||||||
name = register_data['name']
|
name = register_data['name']
|
||||||
|
@ -88,7 +86,7 @@ def register():
|
||||||
return jsonify({'result': '注册成功'})
|
return jsonify({'result': '注册成功'})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/student/get_lesson', methods=['GET'])
|
@app.route('/api/student/get_lesson', methods=['GET'])
|
||||||
def get_lesson(): # 获取课程
|
def get_lesson(): # 获取课程
|
||||||
student_id = session.get('id')
|
student_id = session.get('id')
|
||||||
student_lesson = get_lesson_func(student_id)
|
student_lesson = get_lesson_func(student_id)
|
||||||
|
@ -97,27 +95,27 @@ def get_lesson(): # 获取课程
|
||||||
|
|
||||||
|
|
||||||
# 学生获取试卷
|
# 学生获取试卷
|
||||||
@app.route('/student/get_test', methods=['POST'])
|
@app.route('/api/student/get_test', methods=['POST'])
|
||||||
def get_test(): # 获取试卷以及历史试卷
|
def get_test(): # 获取试卷以及历史试卷
|
||||||
data = request.json
|
data = request.json
|
||||||
ID = data['student_ID']
|
ID = data['student_ID']
|
||||||
return jsonify({"data": fetch_test_func(ID)})
|
return jsonify({"data": fetch_test_func(ID)})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/student/fetch_result', methods=['POST']) # 查找成绩
|
@app.route('/api/student/fetch_result', methods=['POST']) # 查找成绩
|
||||||
def fetch_result():
|
def fetch_result():
|
||||||
data = request.json
|
data = request.json
|
||||||
ID = data['student_ID']
|
ID = data['student_ID']
|
||||||
return jsonify({'result': fetch_result_func(ID)})
|
return jsonify({'result': fetch_result_func(ID)})
|
||||||
|
|
||||||
@app.route('/student/get_end_student', methods=['POST'])
|
@app.route('/api/student/get_end_student', methods=['POST'])
|
||||||
def get_end_student():
|
def get_end_student():
|
||||||
data = request.json
|
data = request.json
|
||||||
ID = data['student_ID']
|
ID = data['student_ID']
|
||||||
return jsonify({'result': find_end_test(ID)})
|
return jsonify({'result': find_end_test(ID)})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/student/score_entry', methods=['POST'])
|
@app.route('/api/student/score_entry', methods=['POST'])
|
||||||
def score_entry():
|
def score_entry():
|
||||||
data = request.json
|
data = request.json
|
||||||
ID = data['student_ID']
|
ID = data['student_ID']
|
||||||
|
@ -128,8 +126,24 @@ def score_entry():
|
||||||
return jsonify({'result': '成功'})
|
return jsonify({'result': '成功'})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/student/FetchTrainTitle',methods=['POST'])
|
||||||
|
def FetchTrainTitle():
|
||||||
|
data = request.json
|
||||||
|
ID = data['student_ID']
|
||||||
|
title=FetchTrainTitleFunc(ID)
|
||||||
|
return jsonify({'title': title})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/student/TrainData',methods=['POST'])
|
||||||
|
def TrainData():
|
||||||
|
examID=request.json['operateID']
|
||||||
|
result=FetchTrainTestFunc(examID)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 以下为教师功能—————————————————————————————————————————————————————————————————————
|
# 以下为教师功能—————————————————————————————————————————————————————————————————————
|
||||||
@app.route('/teacher/return_question', methods=['POST'])
|
@app.route('/api/teacher/return_question', methods=['POST'])
|
||||||
def return_question():
|
def return_question():
|
||||||
data = request.json
|
data = request.json
|
||||||
ID = data['teacher_ID']
|
ID = data['teacher_ID']
|
||||||
|
@ -139,7 +153,7 @@ def return_question():
|
||||||
return jsonify({'选择': choice_question, '填空': completion_question, '判断': t_or_f_question})
|
return jsonify({'选择': choice_question, '填空': completion_question, '判断': t_or_f_question})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/teacher/select_class', methods=['POST'])
|
@app.route('/api/teacher/select_class', methods=['POST'])
|
||||||
def select_class(): # 查找每个老师管理的班级 以及在考试管理查找默认班级
|
def select_class(): # 查找每个老师管理的班级 以及在考试管理查找默认班级
|
||||||
teacher_id = request.json['teacher_ID']
|
teacher_id = request.json['teacher_ID']
|
||||||
# testID =request.json['testID']
|
# testID =request.json['testID']
|
||||||
|
@ -148,23 +162,23 @@ def select_class(): # 查找每个老师管理的班级 以及在考试管理
|
||||||
# print(testID)
|
# print(testID)
|
||||||
return jsonify({'Class': class_dic,'default': find_default_class_func(default_class, teacher_id)})
|
return jsonify({'Class': class_dic,'default': find_default_class_func(default_class, teacher_id)})
|
||||||
|
|
||||||
@app.route('/teacher/change_class', methods=['POST'])
|
@app.route('/api/teacher/change_class', methods=['POST'])
|
||||||
def change_class(): # 查找每个老师管理的班级 以及在考试管理查找默认班级
|
def change_class(): # 查找每个老师管理的班级 以及在考试管理查找默认班级
|
||||||
teacher_id = request.json['teacher_ID']
|
teacher_id = request.json['teacher_ID']
|
||||||
ClassID=request.json['selectedValue']
|
ClassID=request.json['selectedValue']
|
||||||
return jsonify({'default': find_default_class_func(ClassID,teacher_id)})
|
return jsonify({'default': find_default_class_func(ClassID,teacher_id)})
|
||||||
|
|
||||||
@app.route('/teacher/detaileddata', methods=['POST'])
|
@app.route('/api/teacher/detaileddata', methods=['POST'])
|
||||||
def detaileddata():
|
def detaileddata():
|
||||||
data=request.json
|
data=request.json
|
||||||
ClassID=data['selectedValue']
|
ClassID=data['selectedValue']
|
||||||
testID=data['testID']
|
testID=data['testID']
|
||||||
return jsonify({'data':detailed_class(testID,ClassID)})
|
return jsonify({'data':detailed_class(testID,ClassID)})
|
||||||
|
|
||||||
@app.route('/teacher/', methods=['POST'])
|
@app.route('/api/teacher/', methods=['POST'])
|
||||||
def find_test():
|
def find_test():
|
||||||
return
|
return
|
||||||
@app.route('/teacher/find_student', methods=['POST'])
|
@app.route('/api/teacher/find_student', methods=['POST'])
|
||||||
def find_student(): # 获取班级学生的具体信息
|
def find_student(): # 获取班级学生的具体信息
|
||||||
student_list = []
|
student_list = []
|
||||||
Data = request.json
|
Data = request.json
|
||||||
|
@ -175,7 +189,7 @@ def find_student(): # 获取班级学生的具体信息
|
||||||
return [student_succeed, student_list]
|
return [student_succeed, student_list]
|
||||||
|
|
||||||
|
|
||||||
@app.route('/teacher/accept_test', methods=['POST']) # 在前端发布成功之后要存入数据库
|
@app.route('/api/teacher/accept_test', methods=['POST']) # 在前端发布成功之后要存入数据库
|
||||||
def accept_test():
|
def accept_test():
|
||||||
data = request.json
|
data = request.json
|
||||||
choice_list = data['ChoiceQuestionSet']
|
choice_list = data['ChoiceQuestionSet']
|
||||||
|
@ -190,11 +204,11 @@ def accept_test():
|
||||||
print('添加成功')
|
print('添加成功')
|
||||||
return jsonify({'result': '发布成功'})
|
return jsonify({'result': '发布成功'})
|
||||||
|
|
||||||
@app.route('/teacher/fetch_train_question',methods=["POST"])
|
@app.route('/api/teacher/fetch_train_question',methods=["POST"])
|
||||||
def fetch_train_question():
|
def fetch_train_question():
|
||||||
return train_question()
|
return train_question()
|
||||||
|
|
||||||
@app.route('/teacher/SendTrainTest',methods=["POST"])
|
@app.route('/api/teacher/SendTrainTest',methods=["POST"])
|
||||||
def SendTrainTest():
|
def SendTrainTest():
|
||||||
data=request.json
|
data=request.json
|
||||||
TrainChoice=data['TrainChoice']
|
TrainChoice=data['TrainChoice']
|
||||||
|
|