7.1
This commit is contained in:
parent
634321d69d
commit
1beb4fdb86
|
@ -1,4 +1,2 @@
|
||||||
.idea
|
.idea
|
||||||
node_modules
|
node_modules
|
||||||
__pycache__
|
|
||||||
public
|
|
|
@ -38,6 +38,7 @@
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"recharts": "^2.12.7",
|
"recharts": "^2.12.7",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
|
"socket.io-client": "^4.7.5",
|
||||||
"stream": "^0.0.2",
|
"stream": "^0.0.2",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
|
@ -4009,6 +4010,11 @@
|
||||||
"@sinonjs/commons": "^1.7.0"
|
"@sinonjs/commons": "^1.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@socket.io/component-emitter": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||||
|
},
|
||||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmmirror.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
"resolved": "https://registry.npmmirror.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||||
|
@ -5441,7 +5447,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/@xterm/xterm": {
|
"node_modules/@xterm/xterm": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@xterm/xterm/-/xterm-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
||||||
},
|
},
|
||||||
"node_modules/@xtuc/ieee754": {
|
"node_modules/@xtuc/ieee754": {
|
||||||
|
@ -7865,6 +7871,46 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/engine.io-client": {
|
||||||
|
"version": "6.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
|
||||||
|
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1",
|
||||||
|
"engine.io-parser": "~5.2.1",
|
||||||
|
"ws": "~8.17.1",
|
||||||
|
"xmlhttprequest-ssl": "~2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-client/node_modules/ws": {
|
||||||
|
"version": "8.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-parser": {
|
||||||
|
"version": "5.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
|
||||||
|
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.16.0",
|
"version": "5.16.0",
|
||||||
"resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
|
"resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
|
||||||
|
@ -16477,6 +16523,32 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/socket.io-client": {
|
||||||
|
"version": "4.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
|
||||||
|
"integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.2",
|
||||||
|
"engine.io-client": "~6.5.2",
|
||||||
|
"socket.io-parser": "~4.2.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socket.io-parser": {
|
||||||
|
"version": "4.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||||
|
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sockjs": {
|
"node_modules/sockjs": {
|
||||||
"version": "0.3.24",
|
"version": "0.3.24",
|
||||||
"resolved": "https://registry.npmmirror.com/sockjs/-/sockjs-0.3.24.tgz",
|
"resolved": "https://registry.npmmirror.com/sockjs/-/sockjs-0.3.24.tgz",
|
||||||
|
@ -18912,6 +18984,14 @@
|
||||||
"resolved": "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz",
|
"resolved": "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/xmlhttprequest-ssl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"recharts": "^2.12.7",
|
"recharts": "^2.12.7",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
|
"socket.io-client": "^4.7.5",
|
||||||
"stream": "^0.0.2",
|
"stream": "^0.0.2",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { Terminal } from "@xterm/xterm";
|
||||||
|
import "@xterm/xterm/css/xterm.css";
|
||||||
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import io, { Socket } from "socket.io-client";
|
||||||
|
|
||||||
|
function base64Decode(encoded: string): string {
|
||||||
|
return atob(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function WebSSH() {
|
||||||
|
const location = useLocation();
|
||||||
|
const terminalObj = useRef<HTMLDivElement | null>(null);
|
||||||
|
const [terminal, setTerminal] = useState<Terminal | null>(null);
|
||||||
|
const [socket, setSocket] = useState<Socket | null>(null);
|
||||||
|
const [ip, setIp] = useState("");
|
||||||
|
const [port, setPort] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const params = new URLSearchParams(location.search);
|
||||||
|
const encodedIp = params.get("ip");
|
||||||
|
const encodedPort = params.get("port");
|
||||||
|
const encodedPassword = params.get("password");
|
||||||
|
|
||||||
|
if (encodedIp && encodedPort && encodedPassword) {
|
||||||
|
setIp(base64Decode(encodedIp));
|
||||||
|
setPort(base64Decode(encodedPort));
|
||||||
|
setPassword(base64Decode(encodedPassword));
|
||||||
|
}
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (terminal === null) {
|
||||||
|
setTerminal(new Terminal());
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (terminal !== null) {
|
||||||
|
terminal.open(terminalObj.current as HTMLDivElement);
|
||||||
|
|
||||||
|
const newSocket = io("ws://36.138.114.105:32087");
|
||||||
|
setSocket(newSocket);
|
||||||
|
|
||||||
|
terminal.onData((data) => {
|
||||||
|
newSocket.emit("input", data);
|
||||||
|
});
|
||||||
|
|
||||||
|
terminal.onSelectionChange(() => {
|
||||||
|
if (terminal.hasSelection()) {
|
||||||
|
navigator.clipboard.writeText(terminal.getSelection());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
newSocket.emit("heartbeat");
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
newSocket.on("output", (data: string) => {
|
||||||
|
terminal.write(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
newSocket.disconnect();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [terminal]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (socket && ip && port && password) {
|
||||||
|
socket.emit("connect_ssh", { ip, port, password });
|
||||||
|
}
|
||||||
|
}, [socket, ip, port, password]);
|
||||||
|
|
||||||
|
function pasteContent(event: React.MouseEvent) {
|
||||||
|
navigator.clipboard.readText().then((content) => {
|
||||||
|
socket?.emit("input", content);
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div ref={terminalObj} onContextMenu={pasteContent} style={{ height: "100vh", width: "100%" }}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -202,9 +202,8 @@
|
||||||
|
|
||||||
.calendar-box span{
|
.calendar-box span{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* top: 20px; */
|
top: 400px;
|
||||||
top: 380px;
|
right: 185px;
|
||||||
right: 160px;
|
|
||||||
}
|
}
|
||||||
.calendar1{
|
.calendar1{
|
||||||
width: 100px;
|
width: 100px;
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { Link } from 'react-router-dom';
|
||||||
import './SendTrain.css'
|
import './SendTrain.css'
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import DatePicker from 'react-datepicker';
|
import DatePicker from 'react-datepicker';
|
||||||
import 'react-datepicker/dist/react-datepicker.css';
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
|
|
||||||
|
|
||||||
function SendTrain(){
|
function SendTrain(){
|
||||||
const teacher_ID=localStorage.getItem('islogin')
|
const teacher_ID=localStorage.getItem('islogin')
|
||||||
|
@ -138,29 +139,17 @@ function SendTrain(){
|
||||||
}
|
}
|
||||||
|
|
||||||
// 日历
|
// 日历
|
||||||
// 用于存储开始日期和结束日期的状态
|
|
||||||
const [startDate, setStartDate] = useState(new Date());
|
const [startDate, setStartDate] = useState(new Date());
|
||||||
const [endDate, setEndDate] = useState(new Date());
|
const [endDate, setEndDate] = useState(new Date());
|
||||||
// 格式化日期显示
|
// 处理开始时间选择
|
||||||
const formatDate = (date) => {
|
|
||||||
return date.toLocaleDateString();
|
|
||||||
};
|
|
||||||
// 选择日期时更新状态
|
|
||||||
const handleStartDateChange = (date) => {
|
const handleStartDateChange = (date) => {
|
||||||
setStartDate(date);
|
setStartDate(date);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理结束时间选择
|
||||||
const handleEndDateChange = (date) => {
|
const handleEndDateChange = (date) => {
|
||||||
setEndDate(date);
|
setEndDate(date);
|
||||||
};
|
};
|
||||||
// 计算并显示总天数
|
|
||||||
const calculateTotalDays = () => {
|
|
||||||
const differenceInTime = endDate - startDate;
|
|
||||||
const differenceInDays = Math.floor(differenceInTime / (1000 * 60 * 60 * 24));
|
|
||||||
return differenceInDays;
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(calculateTotalDays());
|
|
||||||
}, [startDate, endDate]);
|
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className='SendTrain_body'>
|
<div className='SendTrain_body'>
|
||||||
|
@ -346,27 +335,32 @@ function SendTrain(){
|
||||||
{/* 日历 */}
|
{/* 日历 */}
|
||||||
<p>请填写考试开始、截止日期</p>
|
<p>请填写考试开始、截止日期</p>
|
||||||
<div className='calendar-box'>
|
<div className='calendar-box'>
|
||||||
|
{/* 开始时间输入框 */}
|
||||||
|
<div className='start-date-input'>
|
||||||
|
{/* 日历组件 */}
|
||||||
|
<div className='calendar-picker'>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={startDate}
|
selected={startDate}
|
||||||
onChange={handleStartDateChange}
|
onChange={handleStartDateChange}
|
||||||
dateFormat="yyyy/MM/dd"
|
dateFormat="yyyy-MM-dd HH:mm"
|
||||||
placeholderText="选择开始日期"
|
showTimeSelect
|
||||||
popperPlacement="left-start"
|
timeIntervals={10} // 时间选择间隔,单位为分钟
|
||||||
className='calendar1'
|
timeCaption="time"
|
||||||
|
minDate={new Date()} // 不能选择过去的日期
|
||||||
/>
|
/>
|
||||||
<span>-</span>
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={endDate}
|
selected={endDate}
|
||||||
onChange={handleEndDateChange}
|
onChange={handleEndDateChange}
|
||||||
dateFormat="yyyy/MM/dd"
|
dateFormat="yyyy-MM-dd HH:mm"
|
||||||
placeholderText="选择结束日期"
|
showTimeSelect
|
||||||
minDate={startDate} // 设置最小日期为开始日期
|
timeIntervals={10}
|
||||||
withFullScreenPortal={false} // 避免全屏模式
|
timeCaption="time"
|
||||||
popperPlacement="left-start"
|
minDate={startDate || new Date()} // 结束日期不能早于开始日期
|
||||||
className='calendar2'
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className='data-num'>总天数:{calculateTotalDays()}天</p>
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,11 +11,10 @@ import { max, min } from 'lodash';
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
function Home(){
|
function Home(){
|
||||||
const [isChecked,setisChecked]=useState(false)
|
|
||||||
const student_ID=localStorage.getItem('islogin')
|
const student_ID=localStorage.getItem('islogin')
|
||||||
if(student_ID==null){
|
if(student_ID==null){
|
||||||
|
window.location.href='http://localhost:3000/signin'
|
||||||
alert('未登录,请先前往登录')
|
alert('未登录,请先前往登录')
|
||||||
window.location.href='http://36.138.114.105:30294/'
|
|
||||||
}
|
}
|
||||||
//课表数据
|
//课表数据
|
||||||
const [lesson, setLesson] = useState([]);
|
const [lesson, setLesson] = useState([]);
|
||||||
|
|
|
@ -120,3 +120,12 @@
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.body-right1-exam{
|
||||||
|
width: 1414px;
|
||||||
|
height: 1540px;
|
||||||
|
position: absolute;
|
||||||
|
top: 64px;
|
||||||
|
left: 230px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
}
|
|
@ -10,10 +10,66 @@ import top from '../img/top.jpg'
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
function Exam() {
|
function Exam() {
|
||||||
|
|
||||||
|
|
||||||
//倒计时
|
//倒计时
|
||||||
const [countdown, setCountdown] = useState(null);
|
const [countdown, setCountdown] = useState(null);
|
||||||
|
const {examId}=useParams()
|
||||||
|
const student_ID=localStorage.getItem('islogin')
|
||||||
|
const [score,setscore]=useState(0)
|
||||||
|
const [isEntry,setisEntry]=useState(false)
|
||||||
|
|
||||||
|
//获取题目
|
||||||
|
const [TestData,setTestData]=useState()
|
||||||
|
const TestFunc=async ()=>{
|
||||||
|
try{
|
||||||
|
const TestSrc=await axios.post('/api/student/TestData',{
|
||||||
|
examId
|
||||||
|
})
|
||||||
|
const data=TestSrc.data
|
||||||
|
setTestData(data)
|
||||||
|
}catch{
|
||||||
|
alert('TestSrc出错')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
TestFunc()
|
||||||
|
},[])
|
||||||
|
|
||||||
|
|
||||||
|
//添加成绩
|
||||||
|
const scoreEntry=async()=>{
|
||||||
|
try{
|
||||||
|
const scoreEntrySrc=await axios.post('/api/student/score_entry',{
|
||||||
|
student_ID,
|
||||||
|
examId,
|
||||||
|
score
|
||||||
|
})
|
||||||
|
}catch{
|
||||||
|
alert('scoreEntry出错')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(isEntry){
|
||||||
|
scoreEntry()
|
||||||
|
}
|
||||||
|
},[score])
|
||||||
|
|
||||||
|
function daojishi(){
|
||||||
|
if(localStorage.getItem('time')){
|
||||||
|
setCountdown(localStorage.getItem('time'))
|
||||||
|
}else{
|
||||||
|
if(TestData){
|
||||||
|
setCountdown(60 * parseInt(TestData['examID'][3]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
daojishi()
|
||||||
|
console.log('a');
|
||||||
|
},[TestData])
|
||||||
|
|
||||||
|
|
||||||
// 倒计时更新
|
// 倒计时更新
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -24,18 +80,21 @@ function Exam() {
|
||||||
} else {
|
} else {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
alert('考试时间到!');
|
alert('考试时间到!');
|
||||||
|
correct()
|
||||||
|
window.location.href='http://localhost:3000/subject'
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [countdown]);
|
}, [countdown]);
|
||||||
|
|
||||||
// useEffect(()=>{
|
useEffect(()=>{
|
||||||
// if(countdown<0){
|
if(countdown<0){
|
||||||
// console.log('c');
|
localStorage.removeItem('time')
|
||||||
// setCountdown(60 * parseInt(TrainData['operateID'][4]))
|
setCountdown(60 * parseInt(TestData['examID'][3]))
|
||||||
// localStorage.removeItem('time')
|
|
||||||
// }
|
}
|
||||||
// },[TrainData])
|
},[TestData])
|
||||||
|
|
||||||
|
|
||||||
// 转换秒数为时分秒格式
|
// 转换秒数为时分秒格式
|
||||||
const formatTime = (seconds) => {
|
const formatTime = (seconds) => {
|
||||||
|
@ -48,6 +107,109 @@ function Exam() {
|
||||||
// 下拉菜单
|
// 下拉菜单
|
||||||
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 [answeredChoice, setAnsweredChoice] = useState([]);
|
||||||
|
const [answeredComple, setAnsweredComple] = useState([]);
|
||||||
|
const [answeredJudge, setAnsweredJudge] = 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);
|
||||||
|
// 更新已做题目的状态
|
||||||
|
if (!answeredChoice.includes(key)) {
|
||||||
|
setAnsweredChoice([...answeredChoice, key]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//填空题
|
||||||
|
const handleInputChange = (event) => {
|
||||||
|
const { name, value } = event.target;
|
||||||
|
setcompletion_answer({
|
||||||
|
...completion_answer,
|
||||||
|
[name]: value
|
||||||
|
});
|
||||||
|
if (!answeredComple.includes(parseInt(name))) {
|
||||||
|
setAnsweredComple([...answeredComple, parseInt(name)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//判断题
|
||||||
|
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)
|
||||||
|
if (!answeredJudge.includes(key)) {
|
||||||
|
setAnsweredJudge([...answeredJudge, key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//批改
|
||||||
|
const correct=()=>{
|
||||||
|
let CHO_sum=0;
|
||||||
|
let COM_sum=0;
|
||||||
|
let JUD_sum=0;
|
||||||
|
for(let item of TestData['examID'][0]){
|
||||||
|
if(item[0][6]===choice_answer[CHO_sum]){
|
||||||
|
setscore(prevscore=>prevscore+5)
|
||||||
|
}
|
||||||
|
CHO_sum++
|
||||||
|
}
|
||||||
|
for(let item of TestData['examID'][1]){
|
||||||
|
if (item[0][2]===completion_answer[COM_sum]) {
|
||||||
|
setscore(prevscore=>prevscore+5)
|
||||||
|
}
|
||||||
|
COM_sum++
|
||||||
|
}
|
||||||
|
for(let item of TestData['examID'][2]){
|
||||||
|
if (item[0][2]===judge_answer[JUD_sum]) {
|
||||||
|
setscore(prevscore=>prevscore+5)
|
||||||
|
}
|
||||||
|
JUD_sum++
|
||||||
|
}
|
||||||
|
setisEntry(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const submit=()=>{
|
||||||
|
correct()
|
||||||
|
setCountdown(0)
|
||||||
|
localStorage.removeItem('time')
|
||||||
|
alert('提交成功')
|
||||||
|
window.location.href='http://localhost:3000/subject'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 题目预览框
|
||||||
|
const [isFixed,setIsFixed]=useState(false)
|
||||||
|
// 创建一个函数来处理滚动逻辑
|
||||||
|
const handleScroll = () => {
|
||||||
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
|
||||||
|
const fixedThreshold = 100; // 滚动到100px后固定
|
||||||
|
|
||||||
|
if (scrollTop > fixedThreshold) {
|
||||||
|
setIsFixed(true);
|
||||||
|
} else {
|
||||||
|
setIsFixed(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 在组件挂载后添加滚动事件监听器,并在卸载时移除
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('scroll', handleScroll);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='nav-exam'>
|
<div className='nav-exam'>
|
||||||
|
@ -78,32 +240,99 @@ function Exam() {
|
||||||
</ul>
|
</ul>
|
||||||
{/* 题目预览框 */}
|
{/* 题目预览框 */}
|
||||||
{/* 根据isFixed状态来设置countBox的类 */}
|
{/* 根据isFixed状态来设置countBox的类 */}
|
||||||
{/* <div className={`countBox ${isFixed ? 'fixed-count-box' : ''}`}>
|
<div className={`countBox ${isFixed ? 'fixed-count-box' : ''}`}> {/* 根据isFixed状态来设置countBox的类 */}
|
||||||
{TrainData&&<table>
|
{TestData&&<table>
|
||||||
<tr>选择题:</tr>
|
<tr>选择题:</tr>
|
||||||
<div>
|
<div>
|
||||||
{Object.keys(TrainData['operateID'][0]).map((key,index)=>(
|
{Object.keys(TestData['examID'][0]).map((key,index)=>(
|
||||||
<td key={key} className={answeredChoice.includes(index) ? 'answered' : ''}>{index+1}</td>
|
<td key={key} className={answeredChoice.includes(index) ? 'answered' : ''}>{index+1}</td>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<tr>填空题:</tr>
|
<tr>填空题:</tr>
|
||||||
<div>
|
<div>
|
||||||
{Object.keys(TrainData['operateID'][1]).map((key,index)=>(
|
{Object.keys(TestData['examID'][1]).map((key,index)=>(
|
||||||
<td key={key} className={answeredComple.includes(index) ? 'answered' : ''}>{index+1}</td>
|
<td key={key} className={answeredComple.includes(index) ? 'answered' : ''}>{index+1}</td>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<tr>判断题:</tr>
|
<tr>判断题:</tr>
|
||||||
<div>
|
<div>
|
||||||
{Object.keys(TrainData['operateID'][2]).map((key,index)=>(
|
{Object.keys(TestData['examID'][2]).map((key,index)=>(
|
||||||
<td key={key} className={answeredJudge.includes(index) ? 'answered' : ''}>{index+1}</td>
|
<td key={key} className={answeredJudge.includes(index) ? 'answered' : ''}>{index+1}</td>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</table>}
|
</table>}
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
{/* <div className='body-right1-exam'>
|
|
||||||
|
|
||||||
</div> */}
|
</div>
|
||||||
|
<div className='body-right1'>
|
||||||
|
{TestData&&<table>
|
||||||
|
<p>选择题</p>
|
||||||
|
<tbody>
|
||||||
|
{Object.keys(TestData['examID'][0]).map((key,index) => (
|
||||||
|
<tr key={key}>
|
||||||
|
<tr className='test-title'>{index+1}.{TestData['examID'][0][key][0][1]}</tr>
|
||||||
|
<div className='optionBox'>
|
||||||
|
<label>
|
||||||
|
<input type="radio" value={TestData['examID'][0][key][0][2]} checked={choice_answer[key] === TestData['examID'][0][key][0][2]} onChange={handleOptionChange} name={`group${key}`}/>
|
||||||
|
<span>A.{TestData['examID'][0][key][0][2]}</span>
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
<label>
|
||||||
|
<input type="radio" value={TestData['examID'][0][key][0][3]} checked={choice_answer[key] === TestData['examID'][0][key][0][3]} onChange={handleOptionChange} name={`group${key}`}/>
|
||||||
|
<span>B.{TestData['examID'][0][key][0][3]}</span>
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
<label>
|
||||||
|
<input type="radio" value={TestData['examID'][0][key][0][4]} checked={choice_answer[key] === TestData['examID'][0][key][0][4]} onChange={handleOptionChange} name={`group${key}`}/>
|
||||||
|
<span>C.{TestData['examID'][0][key][0][4]}</span>
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
<label>
|
||||||
|
<input type="radio" value={TestData['examID'][0][key][0][5]} checked={choice_answer[key] === TestData['examID'][0][key][0][5]} onChange={handleOptionChange} name={`group${key}`}/>
|
||||||
|
<span>D.{TestData['examID'][0][key][0][5]}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>}
|
||||||
|
|
||||||
|
{TestData&&(
|
||||||
|
<table className='body-right1-comple'>
|
||||||
|
<tbody>
|
||||||
|
<p>填空题</p>
|
||||||
|
{Object.keys(TestData['examID'][1]).map((key,index)=>(
|
||||||
|
<tr key={key}>
|
||||||
|
<tr className='test-title1'>{index+1}.{TestData['examID'][1][key][0][1]}</tr>
|
||||||
|
{/* <br /> */}
|
||||||
|
<div className='input-box'>
|
||||||
|
<span>请填入你的答案:</span>
|
||||||
|
<input type="text" onChange={handleInputChange} name={key} value={completion_answer[key]||''}/>
|
||||||
|
</div>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{TestData&&(
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<p>判断题</p>
|
||||||
|
{Object.keys(TestData['examID'][2]).map((key,index)=>(
|
||||||
|
<tr key={key} className='panduan-box'>
|
||||||
|
<tr>{index+1}.{TestData['examID'][2][key][0][1]}</tr>
|
||||||
|
<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={submit}>提交</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -57,9 +57,8 @@ function SubjectPage(){
|
||||||
))}
|
))}
|
||||||
</div>}
|
</div>}
|
||||||
<h3>已结束或完成的试卷与练习</h3>
|
<h3>已结束或完成的试卷与练习</h3>
|
||||||
{ testdata&& result&&<div className='test-subject'>
|
<div className='test-subject'>
|
||||||
{Object.keys(testdata).map((key)=>{
|
{ Object.keys(testdata).slice(-3).reverse().map((key) => (
|
||||||
return(
|
|
||||||
<div className='test-box' key={key}>
|
<div className='test-box' key={key}>
|
||||||
<p>试卷ID:{testdata[key][0][3]}</p>
|
<p>试卷ID:{testdata[key][0][3]}</p>
|
||||||
<span>发布者:{'小陈老师'}</span>
|
<span>发布者:{'小陈老师'}</span>
|
||||||
|
@ -67,9 +66,9 @@ function SubjectPage(){
|
||||||
<div>截至时间:{testdata[key][1][0][6]}</div>
|
<div>截至时间:{testdata[key][1][0][6]}</div>
|
||||||
<div id='score'>{testdata[key][0][5]}</div>
|
<div id='score'>{testdata[key][0][5]}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
))}
|
||||||
})}
|
</div>
|
||||||
</div>}
|
<button>更多历史</button>
|
||||||
{ NotFalse&& result&&<div className='test-subject'>
|
{ NotFalse&& result&&<div className='test-subject'>
|
||||||
{Object.keys(NotFalse).map((key)=>{
|
{Object.keys(NotFalse).map((key)=>{
|
||||||
return(
|
return(
|
||||||
|
|
|
@ -16,19 +16,9 @@ function Operation1() {
|
||||||
console.log(60 * parseInt(TrainData['operateID'][4]));
|
console.log(60 * parseInt(TrainData['operateID'][4]));
|
||||||
}
|
}
|
||||||
const clear=()=>{
|
const clear=()=>{
|
||||||
localStorage.removeItem('choice_answers');
|
['time', 'choice_answers', 'completion_answer', 'judge_answer',
|
||||||
setchoice_answer({})
|
'answeredChoice', 'answeredComple', 'answeredJudge', 'RemainingTime', 'TrainData']
|
||||||
localStorage.removeItem('completion_answer')
|
.forEach(item => localStorage.removeItem(item));
|
||||||
setcompletion_answer({})
|
|
||||||
localStorage.removeItem('judge_answer')
|
|
||||||
setjudge_answer({})
|
|
||||||
localStorage.removeItem('answeredChoice')
|
|
||||||
setAnsweredChoice([])
|
|
||||||
localStorage.removeItem('answeredComple')
|
|
||||||
setAnsweredComple([])
|
|
||||||
localStorage.removeItem('answeredJudge')
|
|
||||||
setAnsweredJudge([])
|
|
||||||
localStorage.removeItem('RemainingTime')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { operateID } = useParams();
|
const { operateID } = useParams();
|
||||||
|
@ -85,7 +75,6 @@ function Operation1() {
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(countdown<0){
|
if(countdown<0){
|
||||||
console.log('c');
|
|
||||||
setCountdown(60 * parseInt(TrainData['operateID'][4]))
|
setCountdown(60 * parseInt(TrainData['operateID'][4]))
|
||||||
localStorage.removeItem('time')
|
localStorage.removeItem('time')
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,8 +146,16 @@ function Operation2() {
|
||||||
const tijiao = ()=>{
|
const tijiao = ()=>{
|
||||||
setCountdown(0)
|
setCountdown(0)
|
||||||
localStorage.removeItem('time')
|
localStorage.removeItem('time')
|
||||||
|
localStorage.removeItem('choice_answers');
|
||||||
|
localStorage.removeItem('completion_answer')
|
||||||
|
localStorage.removeItem('judge_answer')
|
||||||
|
localStorage.removeItem('answeredChoice')
|
||||||
|
localStorage.removeItem('answeredComple')
|
||||||
|
localStorage.removeItem('answeredJudge')
|
||||||
|
localStorage.removeItem('RemainingTime')
|
||||||
alert('提交成功')
|
alert('提交成功')
|
||||||
window.location.href='http://localhost:3000/train'
|
window.location.href='http://localhost:3000/train'
|
||||||
|
localStorage.removeItem('TrainData')
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -184,7 +192,7 @@ function Operation2() {
|
||||||
|
|
||||||
<button onClick={click}>测试按钮</button>
|
<button onClick={click}>测试按钮</button>
|
||||||
{/* 前端连接数据库⬇ */}
|
{/* 前端连接数据库⬇ */}
|
||||||
{ !isTrue&&<div>
|
{ !isTrue&&TrainData&&<div>
|
||||||
<Link to={Src}>{TrainData['operateID'][3][0]}</Link>
|
<Link to={Src}>{TrainData['operateID'][3][0]}</Link>
|
||||||
<br />
|
<br />
|
||||||
点击以上链接前往实训
|
点击以上链接前往实训
|
||||||
|
@ -192,7 +200,7 @@ function Operation2() {
|
||||||
{/* 前端连接数据库 ⬆*/}
|
{/* 前端连接数据库 ⬆*/}
|
||||||
|
|
||||||
{/* 达梦数据库连接 ⬇*/}
|
{/* 达梦数据库连接 ⬇*/}
|
||||||
{ isTrue&&
|
{ isTrue&&TrainData&&
|
||||||
<div>
|
<div>
|
||||||
<p>{TrainData['operateID'][3][0]}</p>
|
<p>{TrainData['operateID'][3][0]}</p>
|
||||||
<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>
|
||||||
|
|
|
@ -23,11 +23,12 @@ import ClassID from '../TeacherPages/classlistpages/classId';
|
||||||
import ManageTest from '../TeacherPages/TestManage/ManageTest';
|
import ManageTest from '../TeacherPages/TestManage/ManageTest';
|
||||||
import SendTest from '../TeacherPages/TestManage/SendTest';
|
import SendTest from '../TeacherPages/TestManage/SendTest';
|
||||||
import Marking from '../TeacherPages/MarkingPages/Marking';
|
import Marking from '../TeacherPages/MarkingPages/Marking';
|
||||||
import SendTrain from '../TeacherPages/TrainManage/SendTrain'
|
|
||||||
import TrainManage from '../TeacherPages/TrainManage/Trainmanage'
|
|
||||||
import StudentLink from '../TeacherPages/MarkingPages/StudentLink';
|
import StudentLink from '../TeacherPages/MarkingPages/StudentLink';
|
||||||
|
|
||||||
|
|
||||||
|
import SendTrain from '../TeacherPages/TrainManage/SendTrain';
|
||||||
|
import TrainManage from '../TeacherPages/TrainManage/Trainmanage';
|
||||||
|
import Test from "../TeacherPages/teacherManagetest/Test.tsx"
|
||||||
// 定义一个组件来包裹除了特定页面(exam)外的所有页面使其有导航
|
// 定义一个组件来包裹除了特定页面(exam)外的所有页面使其有导航
|
||||||
const MainLayout = ({ headerNav:HeaderNav }) => {
|
const MainLayout = ({ headerNav:HeaderNav }) => {
|
||||||
return (
|
return (
|
||||||
|
@ -69,6 +70,7 @@ function App() {
|
||||||
<Route path="/classID/:key" element={<MainLayout headerNav={HeaderNavTeacher} />}>
|
<Route path="/classID/:key" element={<MainLayout headerNav={HeaderNavTeacher} />}>
|
||||||
<Route index element={<ClassID/>} />
|
<Route index element={<ClassID/>} />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route path="test" element={<Test />}/>
|
||||||
|
|
||||||
{/* 页面使用单独的布局,不包含HeaderNav和HeaderNavTeacher */}
|
{/* 页面使用单独的布局,不包含HeaderNav和HeaderNavTeacher */}
|
||||||
<Route path="exam/:examId" element={<Exam />} />{/* 练习-考试页面 */}
|
<Route path="exam/:examId" element={<Exam />} />{/* 练习-考试页面 */}
|
||||||
|
|
14
build.sh
14
build.sh
|
@ -20,13 +20,14 @@ build_image() {
|
||||||
|
|
||||||
# 推送镜像
|
# 推送镜像
|
||||||
push_image() {
|
push_image() {
|
||||||
|
local service_name=$1
|
||||||
read -p "是否要推送到《达梦启元云原生大数据平台》? [Y/N] " confirm
|
read -p "是否要推送到《达梦启元云原生大数据平台》? [Y/N] " confirm
|
||||||
if [[ $confirm =~ ^[yY]([eE][sS])?$ ]]; then
|
if [[ $confirm =~ ^[yY]([eE][sS])?$ ]]; then
|
||||||
echo "tag"
|
echo "${service_name} tag"
|
||||||
docker tag "${current_dir}-flask-app" 36.138.114.105:31000/cnsof50011836/flask-app
|
docker tag "${service_name}" 36.138.114.105:31000/cnsof50011836/$service_name
|
||||||
echo "pushing"
|
echo "${service_name} pushing"
|
||||||
docker push 36.138.114.105:31000/cnsof50011836/flask-app
|
docker push 36.138.114.105:31000/cnsof50011836/$service_name
|
||||||
echo "pushed"
|
echo "${service_name} pushed"
|
||||||
else
|
else
|
||||||
echo "用户选择不推送镜像"
|
echo "用户选择不推送镜像"
|
||||||
fi
|
fi
|
||||||
|
@ -43,7 +44,8 @@ main() {
|
||||||
build_image build-frontend
|
build_image build-frontend
|
||||||
build_image flask-app
|
build_image flask-app
|
||||||
|
|
||||||
push_image
|
push_image flask-app
|
||||||
|
push_image base-dm
|
||||||
|
|
||||||
echo "脚本结束"
|
echo "脚本结束"
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,11 @@ services:
|
||||||
flask-app:
|
flask-app:
|
||||||
build: ./python
|
build: ./python
|
||||||
restart: always
|
restart: always
|
||||||
|
image: flask-app
|
||||||
depends_on:
|
depends_on:
|
||||||
- base-dm
|
- base-dm
|
||||||
ports:
|
ports:
|
||||||
- '8000:8000'
|
- '8000:8000'
|
||||||
healthcheck:
|
- '8765:8765'
|
||||||
test: ["CMD-SHELL", "curl --silent --fail localhost:8000/flask-health-check || exit 1"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 10s
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ RUN useradd -m -s /bin/bash dmdba \
|
||||||
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 \
|
&& unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||||
&& chown -R dmdba:dmdba /home/dmdba \
|
&& chown -R dmdba:dmdba /home/dmdba \
|
||||||
&& rm -f dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
&& rm -f 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 \
|
||||||
|
|
|
@ -9,6 +9,8 @@ RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.l
|
||||||
&& 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-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) \
|
&& apt install -y $(check-language-support) \
|
||||||
|
&& sed -i 's/^#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
|
||||||
|
&& sudo sed -i 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config \
|
||||||
&& echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \
|
&& 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 \
|
&& sudo /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \
|
||||||
&& locale-gen \
|
&& locale-gen \
|
||||||
|
|
|
@ -1,26 +1 @@
|
||||||
FROM ubuntu
|
FROM base-dm
|
||||||
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 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 \
|
|
||||||
# 修改用户密码
|
|
||||||
&& echo "dmdba:123456" | chpasswd
|
|
||||||
# 传入安装包并解压
|
|
||||||
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 unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
|
||||||
&& chown -R dmdba:dmdba /home/dmdba \
|
|
||||||
&& rm -f dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
|
||||||
&& 7z x dm8_20240408_x86_rh7_64.iso \
|
|
||||||
&& rm -f dm8_20240408_x86_rh7_64.iso \
|
|
||||||
&& chmod +x DMInstall.bin
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
SHELL=/bin/bash
|
||||||
|
KUBERNETES_SERVICE_PORT_HTTPS=443
|
||||||
|
KUBERNETES_SERVICE_PORT=443
|
||||||
|
HOSTNAME=flask-app-deployment-76d66d98b8-s6hxs
|
||||||
|
DMCCA_CANVAS_NAME=flask-app
|
||||||
|
PWD=/home/flask
|
||||||
|
LOGNAME=flask
|
||||||
|
TZ=Asia/Shanghai
|
||||||
|
HOME=/home/flask
|
||||||
|
LANG=zh_CN.UTF-8
|
||||||
|
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
|
||||||
|
VIRTUAL_ENV=/home/flask/venv
|
||||||
|
TERM=xterm
|
||||||
|
USER=flask
|
||||||
|
DMCCA_CANVAS_NAMESPACE=cnsof50011836-system
|
||||||
|
SHLVL=2
|
||||||
|
KUBERNETES_PORT_443_TCP_PROTO=tcp
|
||||||
|
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
|
||||||
|
KUBERNETES_SERVICE_HOST=10.96.0.1
|
||||||
|
LC_ALL=zh_CN.UTF-8
|
||||||
|
KUBERNETES_PORT=tcp://10.96.0.1:443
|
||||||
|
KUBERNETES_PORT_443_TCP_PORT=443
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
|
||||||
|
MAIL=/var/mail/flask
|
||||||
|
DEBIAN_FRONTEND=noninteractive
|
||||||
|
OLDPWD=/root
|
||||||
|
_=/usr/bin/printenv
|
|
@ -0,0 +1,3 @@
|
||||||
|
.idea
|
||||||
|
__pycache__
|
||||||
|
public
|
|
@ -4,10 +4,12 @@ FROM base
|
||||||
RUN pip install --upgrade pip
|
RUN pip install --upgrade pip
|
||||||
|
|
||||||
# 创建一个用户运行flask
|
# 创建一个用户运行flask
|
||||||
RUN adduser flask && \
|
RUN useradd -m -s /bin/bash flask && \
|
||||||
chown -R flask:flask /home/flask && \
|
chown -R flask:flask /home/flask && \
|
||||||
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 && \
|
||||||
chown -R flask:flask /var/log/flask-app
|
chown -R flask:flask /var/log/flask-app && \
|
||||||
|
service ssh start && \
|
||||||
|
service ssh restart
|
||||||
WORKDIR /home/flask
|
WORKDIR /home/flask
|
||||||
USER flask
|
USER flask
|
||||||
|
|
||||||
|
@ -24,10 +26,12 @@ RUN python3 -m venv "$VIRTUAL_ENV" && \
|
||||||
export FLASK_APP=app.py && \
|
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 && \
|
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
|
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/
|
||||||
|
|
||||||
# 暴露端口
|
# 暴露端口
|
||||||
EXPOSE 5000
|
EXPOSE 8000 22 8765
|
||||||
|
USER root
|
||||||
|
|
||||||
CMD ["gunicorn", "-w", "3", "-t", "60", "-b", "0.0.0.0:8000", "app:app"]
|
CMD ["gunicorn", "-w", "3", "-t", "60", "-b", "0.0.0.0:8000", "app:app"]
|
|
@ -1,12 +1,28 @@
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
import paramiko
|
||||||
|
|
||||||
from teacher_func import *
|
from teacher_func import *
|
||||||
from student_func import *
|
from student_func import *
|
||||||
|
|
||||||
from flask import Flask, render_template, request, jsonify, send_from_directory, session
|
from flask import Flask, render_template, request, jsonify, send_from_directory, session
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
from flask_socketio import SocketIO, emit, disconnect
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
app = Flask(__name__, static_folder="public")
|
app = Flask(__name__, static_folder="public")
|
||||||
CORS(app, resources={r"/*": {"origins": "*"}})
|
CORS(app)
|
||||||
|
cors = CORS(app, resource={
|
||||||
|
r"/*":{
|
||||||
|
"origins":"*"
|
||||||
|
}
|
||||||
|
})
|
||||||
app.config['SECRET_KEY'] = '350625'
|
app.config['SECRET_KEY'] = '350625'
|
||||||
|
socketio = SocketIO(app, cors_allowed_origins="*")
|
||||||
|
|
||||||
|
clients = {}
|
||||||
|
|
||||||
@app.route('/api/student', methods=['POST']) # 检测历史是否登录过,登录则直接进入index,反之则进去login界面
|
@app.route('/api/student', methods=['POST']) # 检测历史是否登录过,登录则直接进入index,反之则进去login界面
|
||||||
def student(): # 判断是否已经登录
|
def student(): # 判断是否已经登录
|
||||||
|
@ -103,10 +119,11 @@ def get_test(): # 获取试卷以及历史试卷
|
||||||
result2=falseTest_func(ID)
|
result2=falseTest_func(ID)
|
||||||
return jsonify({"True":result1,'FalseTest':result2})
|
return jsonify({"True":result1,'FalseTest':result2})
|
||||||
|
|
||||||
@app.route('/api/student/get_testID',methods=['POST'])
|
@app.route('/api/student/TestData',methods=['POST'])
|
||||||
def get_testID(): # 获取试卷ID
|
def TestData(): # 获取试卷ID
|
||||||
ID=request.json['student_ID']
|
examID=request.json['examId']
|
||||||
return jsonify({'data': 'a'})
|
result=TestDataFunc(examID)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/student/fetch_result', methods=['POST']) # 查找成绩
|
@app.route('/api/student/fetch_result', methods=['POST']) # 查找成绩
|
||||||
|
@ -115,11 +132,7 @@ def fetch_result():
|
||||||
ID = data['student_ID']
|
ID = data['student_ID']
|
||||||
return jsonify({'result': fetch_result_func(ID)})
|
return jsonify({'result': fetch_result_func(ID)})
|
||||||
|
|
||||||
@app.route('/api/student/get_end_student', methods=['POST'])
|
|
||||||
def get_end_student():
|
|
||||||
data = request.json
|
|
||||||
ID = data['student_ID']
|
|
||||||
return jsonify({'result': find_end_test(ID)})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/student/score_entry', methods=['POST'])
|
@app.route('/api/student/score_entry', methods=['POST'])
|
||||||
|
@ -183,6 +196,12 @@ 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('/api/teacher/marktrain',methods=['POST'])
|
||||||
|
def mark(): # 批阅试卷
|
||||||
|
ClassID=request.json['ClassID']
|
||||||
|
teacher_ID=request.json['teacher_ID']
|
||||||
|
return jsonify({'MarkClass': MarkTrainFunc(ClassID,teacher_ID)})
|
||||||
|
|
||||||
@app.route('/api/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']
|
||||||
|
@ -242,6 +261,7 @@ def SendTrainTest():
|
||||||
Train=data['Train']
|
Train=data['Train']
|
||||||
teacher_id=data['teacher_ID']
|
teacher_id=data['teacher_ID']
|
||||||
SendTrainTestFunc(TrainChoice, TrainCompletion, TrainJudge, Hour, Min, StopTime,Class,Train,teacher_id)
|
SendTrainTestFunc(TrainChoice, TrainCompletion, TrainJudge, Hour, Min, StopTime,Class,Train,teacher_id)
|
||||||
|
TeacherMark(Class,teacher_id)
|
||||||
return '发布成功'
|
return '发布成功'
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,7 +270,6 @@ def Find_details():
|
||||||
data=request.json
|
data=request.json
|
||||||
ID=data['ID']
|
ID=data['ID']
|
||||||
result=Find_details_Func(ID)
|
result=Find_details_Func(ID)
|
||||||
print(result)
|
|
||||||
return jsonify({'TestScore':result})
|
return jsonify({'TestScore':result})
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,7 +279,56 @@ def catch_all(path = "index.html"):
|
||||||
return send_from_directory("public", path)
|
return send_from_directory("public", path)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('connect_ssh')
|
||||||
|
def handle_connect_ssh(data):
|
||||||
|
ip = data['ip']
|
||||||
|
port = int(data['port'])
|
||||||
|
password = data['password']
|
||||||
|
client_id = request.sid
|
||||||
|
|
||||||
|
ssh_client = paramiko.SSHClient()
|
||||||
|
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
|
||||||
|
try:
|
||||||
|
ssh_client.connect(ip, port=port, username='your-username', password=password)
|
||||||
|
transport = ssh_client.get_transport()
|
||||||
|
channel = transport.open_session()
|
||||||
|
channel.get_pty()
|
||||||
|
channel.invoke_shell()
|
||||||
|
|
||||||
|
clients[client_id] = {
|
||||||
|
'ssh_client': ssh_client,
|
||||||
|
'channel': channel
|
||||||
|
}
|
||||||
|
|
||||||
|
socketio.start_background_task(target=read_from_channel, channel=channel, client_id=client_id)
|
||||||
|
except Exception as e:
|
||||||
|
emit('output', f'Connection failed: {str(e)}')
|
||||||
|
|
||||||
|
|
||||||
|
def read_from_channel(channel, client_id):
|
||||||
|
while True:
|
||||||
|
if channel.recv_ready():
|
||||||
|
data = channel.recv(1024).decode('utf-8')
|
||||||
|
socketio.emit('output', data, room=client_id)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('input')
|
||||||
|
def handle_input(data):
|
||||||
|
client_id = request.sid
|
||||||
|
if client_id in clients:
|
||||||
|
clients[client_id]['channel'].send(data)
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('disconnect')
|
||||||
|
def handle_disconnect():
|
||||||
|
client_id = request.sid
|
||||||
|
if client_id in clients:
|
||||||
|
clients[client_id]['channel'].close()
|
||||||
|
clients[client_id]['ssh_client'].close()
|
||||||
|
del clients[client_id]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
socketio.run(app, host='0.0.0.0', port=5000 ,allow_unsafe_werkzeug=True)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: NAME
|
||||||
|
namespace: ""
|
||||||
|
labels:
|
||||||
|
app: NAME
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: base-dm
|
||||||
|
image: harbor.dameng.io/cnsof50011836/base-dm
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: '1'
|
||||||
|
memory: 1Gi
|
||||||
|
requests:
|
||||||
|
cpu: '0.25'
|
||||||
|
memory: 0.5G
|
|
@ -2,3 +2,7 @@ Flask==2.3.0
|
||||||
Flask_Cors==4.0.0
|
Flask_Cors==4.0.0
|
||||||
pycryptodome==3.19.0
|
pycryptodome==3.19.0
|
||||||
gunicorn
|
gunicorn
|
||||||
|
kubernetes
|
||||||
|
websockets
|
||||||
|
paramiko
|
||||||
|
flask-socketio
|
|
@ -117,10 +117,9 @@ def get_lesson_func(id):
|
||||||
|
|
||||||
def student_succeed_func(ID):
|
def student_succeed_func(ID):
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
cursor.execute(f'SELECT * FROM STUDENT WHERE ID={ID}')
|
cursor.execute(f'SELECT * FROM STUDENT WHERE ID={ID}')# 报错
|
||||||
student_succeed = cursor.fetchall()[0]
|
student_succeed = cursor.fetchall()[0]
|
||||||
student_succeeds = student_succeed[0], student_succeed[1], student_succeed[3], student_succeed[4]
|
student_succeeds = student_succeed[0], student_succeed[1], student_succeed[3], student_succeed[4]
|
||||||
print(student_succeeds)
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
return student_succeeds
|
return student_succeeds
|
||||||
|
|
||||||
|
@ -128,17 +127,27 @@ def student_succeed_func(ID):
|
||||||
# fetch_testID('20240101')
|
# fetch_testID('20240101')
|
||||||
def fetch_test_func(ID):#获取试卷
|
def fetch_test_func(ID):#获取试卷
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
correct=[]
|
||||||
TrueTestDic={}
|
TrueTestDic={}
|
||||||
TruetestID=[]
|
TruetestID=[]
|
||||||
cursor.execute(f"SELECT * FROM STUDENT_TEST WHERE STUDENT_ID=? AND TF='true'",(ID))
|
cursor.execute(f"SELECT * FROM STUDENT_TEST WHERE STUDENT_ID=? AND TF='true'",(ID))
|
||||||
for i in cursor.fetchall():
|
for i in cursor.fetchall():
|
||||||
|
correct.append(i)
|
||||||
|
|
||||||
|
correct=correct[::-1][:3]
|
||||||
|
|
||||||
|
for i in correct:
|
||||||
TruetestID.append(i[3])
|
TruetestID.append(i[3])
|
||||||
TrueTestDic[i[3]]=i
|
TrueTestDic[i[3]]=i
|
||||||
|
|
||||||
|
TruetestID=TruetestID[::-1][:3]
|
||||||
|
|
||||||
for index in TruetestID:
|
for index in TruetestID:
|
||||||
cursor.execute(f"SELECT * FROM TEST_BANK WHERE ID=?",(index))
|
cursor.execute(f"SELECT * FROM TEST_BANK WHERE ID=?",(index))
|
||||||
TrueTestDic[index]=TrueTestDic[index],cursor.fetchall()
|
TrueTestDic[index]=TrueTestDic[index],cursor.fetchall()
|
||||||
|
|
||||||
# print(TrueTestDic)
|
# print(TrueTestDic)
|
||||||
|
|
||||||
return TrueTestDic
|
return TrueTestDic
|
||||||
# fetch_test_func('20240101')
|
# fetch_test_func('20240101')
|
||||||
|
|
||||||
|
@ -166,6 +175,53 @@ def falseTest_func(ID):
|
||||||
|
|
||||||
# falseTest_func('20240101')
|
# falseTest_func('20240101')
|
||||||
|
|
||||||
|
|
||||||
|
def TestDataFunc(examID):
|
||||||
|
cursor = db.cursor()
|
||||||
|
cursor.execute(f"SELECT * FROM TEST_BANK WHERE ID=?",(examID,))
|
||||||
|
TestID=cursor.fetchall()[0]
|
||||||
|
ChoiceList=json.loads(TestID[0])
|
||||||
|
CompleList=json.loads(TestID[1])
|
||||||
|
JudgeList=json.loads(TestID[2])
|
||||||
|
|
||||||
|
Choice=[]
|
||||||
|
Comple=[]
|
||||||
|
Judge=[]
|
||||||
|
|
||||||
|
CHOICE=[str(x) for x in ChoiceList]
|
||||||
|
COMPLE=[str(x) for x in CompleList]
|
||||||
|
JUDGE=[str(x) for x in JudgeList]
|
||||||
|
|
||||||
|
for i in CHOICE:
|
||||||
|
cursor.execute(f"SELECT * FROM CHOICE_QUESTION_BANK WHERE ID=?",(i))
|
||||||
|
Choice.append(cursor.fetchall())
|
||||||
|
|
||||||
|
for i in COMPLE:
|
||||||
|
cursor.execute(f"SELECT * FROM COMPLETION_QUESTION_BANK WHERE ID=?",(i))
|
||||||
|
Comple.append(cursor.fetchall())
|
||||||
|
|
||||||
|
for i in JUDGE:
|
||||||
|
cursor.execute(f"SELECT * FROM T_OR_F_QUESTION_BANK WHERE ID=?",(i))
|
||||||
|
Judge.append(cursor.fetchall())
|
||||||
|
|
||||||
|
|
||||||
|
HOUR=TestID[3]
|
||||||
|
MIN=TestID[4]
|
||||||
|
if int(HOUR)==0:
|
||||||
|
time=int(MIN)
|
||||||
|
elif int(MIN)==0:
|
||||||
|
time=int(HOUR)*60
|
||||||
|
else:
|
||||||
|
time=int(HOUR)*60+int(MIN)
|
||||||
|
|
||||||
|
dic={'examID':[Choice,Comple,Judge,time]}
|
||||||
|
|
||||||
|
# print(dic)
|
||||||
|
|
||||||
|
return dic
|
||||||
|
|
||||||
|
# TestDataFunc('35')
|
||||||
|
|
||||||
# 查找学生已经完成的记录
|
# 查找学生已经完成的记录
|
||||||
def find_end_test(ID):
|
def find_end_test(ID):
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
@ -196,12 +252,22 @@ def FetchTrainTitleFunc(ID):
|
||||||
titles.append(i[2])
|
titles.append(i[2])
|
||||||
|
|
||||||
for i in titles:
|
for i in titles:
|
||||||
cursor.execute('SELECT * FROM TRAINTEST WHERE ID=? ',(i))
|
cursor.execute('SELECT * FROM TRAINTEST WHERE ID=? AND STOPTIME>? ',(i,Time))
|
||||||
title.append(cursor.fetchall())
|
result=cursor.fetchall()
|
||||||
|
title.append(result)
|
||||||
|
if result:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
cursor.execute("UPDATE TRAINSCORE SET TF='true' , RESULT='0' , TRAINRESULT='0' WHERE TEST_ID=? AND STUDENT_ID=?",(i,ID))
|
||||||
|
|
||||||
|
|
||||||
|
title = [item for item in title if item]
|
||||||
|
print(title)
|
||||||
|
db.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
return title
|
return title
|
||||||
|
|
||||||
|
# FetchTrainTitleFunc("20240101")
|
||||||
|
|
||||||
|
|
||||||
def FetchTrainTestFunc(operateID):
|
def FetchTrainTestFunc(operateID):
|
||||||
|
|
|
@ -7,6 +7,8 @@ import datetime
|
||||||
|
|
||||||
db = dmPython.connect(user='SYSDBA', password='dameng!!', host="36.138.114.105", port="32522")
|
db = dmPython.connect(user='SYSDBA', password='dameng!!', host="36.138.114.105", port="32522")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#获取题目
|
#获取题目
|
||||||
def choice_question_func(ID):
|
def choice_question_func(ID):
|
||||||
question_cursor = db.cursor()
|
question_cursor = db.cursor()
|
||||||
|
@ -218,6 +220,9 @@ def train_question():
|
||||||
# print(Train)
|
# print(Train)
|
||||||
return Train
|
return Train
|
||||||
|
|
||||||
|
|
||||||
|
testID=None
|
||||||
|
TrainName=""
|
||||||
# train_question()
|
# train_question()
|
||||||
def SendTrainTestFunc(TrainChoice,TrainCompletion,TrainJudge,Hour,Min,StopTime,Class,Train,teacher_id):
|
def SendTrainTestFunc(TrainChoice,TrainCompletion,TrainJudge,Hour,Min,StopTime,Class,Train,teacher_id):
|
||||||
TrainChoice = json.dumps(TrainChoice)
|
TrainChoice = json.dumps(TrainChoice)
|
||||||
|
@ -225,6 +230,8 @@ def SendTrainTestFunc(TrainChoice,TrainCompletion,TrainJudge,Hour,Min,StopTime,C
|
||||||
TrainJudge = json.dumps(TrainJudge)
|
TrainJudge = json.dumps(TrainJudge)
|
||||||
Class=json.dumps(Class)
|
Class=json.dumps(Class)
|
||||||
Train=json.dumps(Train)
|
Train=json.dumps(Train)
|
||||||
|
global TrainName
|
||||||
|
TrainName=Train
|
||||||
# 获取当前时间
|
# 获取当前时间
|
||||||
now_time = datetime.datetime.now().replace(microsecond=0)
|
now_time = datetime.datetime.now().replace(microsecond=0)
|
||||||
end_time = now_time + datetime.timedelta(days=int(StopTime))
|
end_time = now_time + datetime.timedelta(days=int(StopTime))
|
||||||
|
@ -258,13 +265,27 @@ def SendTrainTestFunc(TrainChoice,TrainCompletion,TrainJudge,Hour,Min,StopTime,C
|
||||||
(i, i[0:6], test_id, end,one))
|
(i, i[0:6], test_id, end,one))
|
||||||
|
|
||||||
# 发布实训的时候根据实训不同给予不同链接
|
# 发布实训的时候根据实训不同给予不同链接
|
||||||
|
cursor.execute(f"SELECT ID FROM TRAINTEST WHERE RELEASETIME=? ", (now_time))
|
||||||
|
test_id = cursor.fetchall()[0][0]
|
||||||
|
global testID
|
||||||
|
testID=test_id
|
||||||
print('分配成功')
|
print('分配成功')
|
||||||
db.commit()
|
db.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
return '发布成功'
|
return '发布成功'
|
||||||
|
|
||||||
|
|
||||||
|
def TeacherMark(CLASS,ID):
|
||||||
|
global testID
|
||||||
|
global TrainName
|
||||||
|
cursor = db.cursor()
|
||||||
|
strClass=str(CLASS)
|
||||||
|
if TrainName.find(r'["\u524d\u7aef\u4e0e\u6570\u636e\u5e93\u7ed3\u5408"]') != -1:
|
||||||
|
for i in eval(strClass):
|
||||||
|
cursor.execute(f'INSERT INTO TEACHERMARK VALUES(?,?,?,?) ', (ID,testID,'false', i))
|
||||||
|
db.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
# def Find_dic(dic):
|
# def Find_dic(dic):
|
||||||
# # 获取字典的键,并按照从大到小的顺序排序
|
# # 获取字典的键,并按照从大到小的顺序排序
|
||||||
# keys_sorted = sorted(dic.keys(), reverse=True)
|
# keys_sorted = sorted(dic.keys(), reverse=True)
|
||||||
|
@ -291,3 +312,17 @@ def Find_details_Func(ID):
|
||||||
return dic
|
return dic
|
||||||
|
|
||||||
# print(Find_details('20240101'))
|
# print(Find_details('20240101'))
|
||||||
|
|
||||||
|
|
||||||
|
#获取未批改的卷子
|
||||||
|
def MarkTrainFunc(ClassID,teacher_ID):
|
||||||
|
dic={}
|
||||||
|
cursor = db.cursor()
|
||||||
|
cursor.execute(f"SELECT * FROM TEACHERMARK WHERE CLASS=? AND TEACHERID=? AND TF='false'", (ClassID,teacher_ID))
|
||||||
|
for i in cursor.fetchall():
|
||||||
|
cursor.execute(f"SELECT * FROM TRAINTEST WHERE ID=? ", (i[1],))
|
||||||
|
dic[i[1]]=cursor.fetchall()
|
||||||
|
# print(dic)
|
||||||
|
return dic
|
||||||
|
|
||||||
|
# MarkTrainFunc('202401','111111')
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
TrainName='["\u524d\u7aef\u4e0e\u6570\u636e\u5e93\u7ed3\u5408"]'
|
||||||
|
print(TrainName)
|
||||||
|
print(type(TrainName))
|
||||||
|
if TrainName == '["\u524d\u7aef\u4e0e\u6570\u636e\u5e93\u7ed3\u5408"]':
|
||||||
|
print('yes')
|
Loading…
Reference in New Issue