diff --git a/.gitignore b/.gitignore index e69de29..0e6481e 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,53 @@ +# OS +.DS_Store +**/.DS_Store +Thumbs.db + +# Editor / local tooling +.cursor/ +.idea/inspectionProfiles/ +*.swp +AES-front/.npmrc +AES-front/pnpm-workspace.yaml + +# Dependencies and build output +node_modules/ +**/node_modules/ +AES/target/ +**/target/ +dist/ +*.class + +# Unrelated local documents +211310132.pdf +211310509.pdf +docs/需求说明.mp4 +docs/通用语音识别_需求说明.mp4 (1).txt +docs/自动评分系统/ + +# Binary / media files (keep already-tracked assets) +*.pdf +*.mp4 +*.mp3 +*.wav +*.zip +*.rar +*.7z +*.doc +*.docx +*.xls +*.xlsx +*.ppt +*.pptx +*.jar +*.war + +# Runtime uploads and empty local dumps +upload/ +dependency-tree.txt +AES/停用词.txt + +# Logs and Python cache +*.log +__pycache__/ +*.pyc diff --git a/AES-front/src/views/user/score-rank/components/personal-rank.vue b/AES-front/src/views/user/score-rank/components/personal-rank.vue index aa77a88..468a4d7 100644 --- a/AES-front/src/views/user/score-rank/components/personal-rank.vue +++ b/AES-front/src/views/user/score-rank/components/personal-rank.vue @@ -54,7 +54,7 @@ const queryExamScores = async () => { params: { examId } }); title.value = res.data.title; // 更新作业名称 - score.value = res.data.score; // 更新个人得分 + score.value = res.data.score || res.data.autoscore; // 更新个人得分 rank.value = res.data.rank || "-"; // 更新个人排名,如果rank为空则显示 "-" }; diff --git a/AES/src/main/resources/application.properties b/AES/src/main/resources/application.properties index e82f2c8..a12d66d 100644 --- a/AES/src/main/resources/application.properties +++ b/AES/src/main/resources/application.properties @@ -5,7 +5,7 @@ server.port=8082 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource jdbc_url=jdbc:mysql://localhost:3306/aes?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=True jdbc_username=root -jdbc_password=13661744518xh +jdbc_password=123456 #spring.datasource.url=jdbc:mysql://localhost:3306/aes?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=True #spring.datasource.username=root #spring.datasource.password=123456 @@ -43,4 +43,8 @@ spring.servlet.multipart.max-request-size=50MB spring.main.allow-bean-definition-overriding=true spring.jackson.serialization-inclusion=non_null + +spring.redis.host=127.0.0.1 +spring.redis.port=6379 +spring.redis.password=hqb@1234 #??null? \ No newline at end of file diff --git a/AES/src/main/resources/spring-hibernate.xml b/AES/src/main/resources/spring-hibernate.xml index 757d89a..2573593 100644 --- a/AES/src/main/resources/spring-hibernate.xml +++ b/AES/src/main/resources/spring-hibernate.xml @@ -16,7 +16,7 @@ https://www.springframework.org/schema/context/spring-context.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> - + @@ -125,7 +125,7 @@ - + diff --git a/docs/aes.sql b/docs/aes.sql new file mode 100644 index 0000000..75024d1 --- /dev/null +++ b/docs/aes.sql @@ -0,0 +1,324 @@ +/* +Navicat MySQL Data Transfer + +Source Server : mydb +Source Server Version : 80027 +Source Host : localhost:3306 +Source Database : aes + +Target Server Type : MYSQL +Target Server Version : 80027 +File Encoding : 65001 + +Date: 2025-05-15 18:42:43 +*/ + +SET FOREIGN_KEY_CHECKS=0; + +-- ---------------------------- +-- Table structure for adminusers +-- ---------------------------- +DROP TABLE IF EXISTS `adminusers`; +CREATE TABLE `adminusers` ( + `id` int NOT NULL AUTO_INCREMENT, + `account` varchar(50) NOT NULL, + `password` varchar(50) NOT NULL, + `name` varchar(50) NOT NULL, + `role` varchar(10) NOT NULL, + `Email` varchar(30) DEFAULT NULL, + `active` int NOT NULL, + `answer` varchar(20) DEFAULT NULL, + `question` varchar(50) DEFAULT NULL, + `uuid` varchar(100) DEFAULT NULL, + `pwd` varchar(64) DEFAULT NULL, + `No` varchar(20) DEFAULT NULL, + `status` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=gbk; + +-- ---------------------------- +-- Records of adminusers +-- ---------------------------- +INSERT INTO `adminusers` VALUES ('1', 'huangturbo', '123456', '黄秋波', 'teacher', '2845141619@qq.com', '1', '', '', '', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', 'null', '待审核'); +INSERT INTO `adminusers` VALUES ('2', 'lxx', '123456', '林筱筱', 'teacher', '', '1', '', '', '', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, '通过'); +INSERT INTO `adminusers` VALUES ('3', 'lt', '123456', '卢婷', 'teacher', '', '1', '', '', '', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, '通过'); +INSERT INTO `adminusers` VALUES ('4', 'admin', '123456', '管理员', 'admin', '', '1', '', '', '', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, null); +INSERT INTO `adminusers` VALUES ('23', 'PeihaiZhao', '123456', 'PeihaiZhao', 'teacher', '', '1', '', '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, '通过'); +INSERT INTO `adminusers` VALUES ('24', '2181802', '123456', '邵雯佩', 'assistant', '', '1', '', '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, null); +INSERT INTO `adminusers` VALUES ('30', 'judge', '123456', '裁判机', 'teacher', '', '1', '', '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, '通过'); +INSERT INTO `adminusers` VALUES ('81', '2222671', '123456', '梁玥', 'assistant', '2845141619@qq.com', '1', '', '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', null, null); +INSERT INTO `adminusers` VALUES ('82', 'huangqiubo', '123456', '黄', 'teacher', '2845141619@qq.com', '1', '', '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', '101042991', '通过'); +INSERT INTO `adminusers` VALUES ('83', 'assis', '123456', '助教', 'assistant', '', '1', '', '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', '123456', null); +INSERT INTO `adminusers` VALUES ('84', 'ds', '123456', 'ds', 'assistant', '', '1', '', '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', '123', null); +INSERT INTO `adminusers` VALUES ('90', '助教添加', '123456', '助教添加', 'assistant', '234567765@qq.com', '1', null, null, null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', '3456213', null); + +-- ---------------------------- +-- Table structure for assistantclass +-- ---------------------------- +DROP TABLE IF EXISTS `assistantclass`; +CREATE TABLE `assistantclass` ( + `id` int NOT NULL AUTO_INCREMENT, + `assistantId` int DEFAULT NULL, + `classId` int DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of assistantclass +-- ---------------------------- +INSERT INTO `assistantclass` VALUES ('1', '24', '1'); +INSERT INTO `assistantclass` VALUES ('2', '24', '2'); +INSERT INTO `assistantclass` VALUES ('13', '24', '7'); +INSERT INTO `assistantclass` VALUES ('14', '83', '7'); +INSERT INTO `assistantclass` VALUES ('16', '90', '8'); +INSERT INTO `assistantclass` VALUES ('17', '90', '9'); +INSERT INTO `assistantclass` VALUES ('20', '90', '13'); + +-- ---------------------------- +-- Table structure for class +-- ---------------------------- +DROP TABLE IF EXISTS `class`; +CREATE TABLE `class` ( + `id` int NOT NULL AUTO_INCREMENT, + `courseId` int DEFAULT NULL, + `teacherId` int NOT NULL, + `name` varchar(50) DEFAULT NULL, + `studentNum` int DEFAULT '0', + `createTime` datetime NOT NULL, + `inviteCode` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of class +-- ---------------------------- +INSERT INTO `class` VALUES ('1', '1', '1', 'c语言1班', '4', '2025-02-20 12:59:40', '52ACTECH'); +INSERT INTO `class` VALUES ('2', '1', '1', 'c语言2班', '0', '2025-02-19 12:59:43', '36WFSDFS'); +INSERT INTO `class` VALUES ('3', '2', '1', 'c++1班', '4', '2025-02-15 12:59:46', '43CHJSCA'); +INSERT INTO `class` VALUES ('5', '1', '1', 'c语言3班', '4', '2025-02-26 12:59:50', '372GDHSJ'); +INSERT INTO `class` VALUES ('7', '2', '23', 'c++2班', '0', '2025-03-12 22:16:22', 'WS88A9LE'); +INSERT INTO `class` VALUES ('8', '9', '1', '数据库1班', '2', '2025-03-14 14:40:59', 'N8URVFY4'); +INSERT INTO `class` VALUES ('9', '9', '2', '数据库2班', '2', '2025-04-20 20:10:53', '2ZP2Z8FR'); +INSERT INTO `class` VALUES ('11', '5', '2', 'java1班', '0', '2025-04-24 14:40:59', 'D95C6U32'); +INSERT INTO `class` VALUES ('12', null, '2', 'java2班', '0', '2025-04-29 13:22:06', 'Y225YJFG'); +INSERT INTO `class` VALUES ('13', null, '2', 'java3班', '5', '2025-04-29 13:22:14', 'NNRKLF3Q'); + +-- ---------------------------- +-- Table structure for course +-- ---------------------------- +DROP TABLE IF EXISTS `course`; +CREATE TABLE `course` ( + `id` int NOT NULL AUTO_INCREMENT, + `adminuserId` int NOT NULL, + `name` varchar(30) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of course +-- ---------------------------- +INSERT INTO `course` VALUES ('1', '1', 'C语言课程'); +INSERT INTO `course` VALUES ('2', '1', 'C++课程'); +INSERT INTO `course` VALUES ('5', '1', 'Java课程'); +INSERT INTO `course` VALUES ('7', '1', 'python课程'); +INSERT INTO `course` VALUES ('8', '1', 'JavaScript课程'); +INSERT INTO `course` VALUES ('9', '2', '数据库课程'); + +-- ---------------------------- +-- Table structure for postproblem +-- ---------------------------- +DROP TABLE IF EXISTS `postproblem`; +CREATE TABLE `postproblem` ( + `id` int NOT NULL AUTO_INCREMENT, + `problemId` int NOT NULL, + `classId` int NOT NULL, + `adminuserId` int NOT NULL, + `startTime` datetime NOT NULL, + `endTime` datetime NOT NULL, + `allow` int NOT NULL DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of postproblem +-- ---------------------------- +INSERT INTO `postproblem` VALUES ('12', '5', '1', '2', '2025-05-01 21:39:15', '2025-05-10 21:39:16', '0'); +INSERT INTO `postproblem` VALUES ('13', '5', '5', '2', '2025-03-20 21:39:15', '2025-05-08 21:39:16', '1'); +INSERT INTO `postproblem` VALUES ('14', '3', '5', '1', '2025-05-02 11:06:22', '2025-05-11 11:06:23', '0'); +INSERT INTO `postproblem` VALUES ('15', '3', '1', '1', '2025-05-08 11:06:22', '2025-05-11 11:06:23', '1'); + +-- ---------------------------- +-- Table structure for problem +-- ---------------------------- +DROP TABLE IF EXISTS `problem`; +CREATE TABLE `problem` ( + `id` int NOT NULL AUTO_INCREMENT, + `courseId` int NOT NULL, + `adminuserId` int NOT NULL, + `title` varchar(30) DEFAULT NULL, + `description` varchar(5000) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of problem +-- ---------------------------- +INSERT INTO `problem` VALUES ('3', '1', '1', '迷宫游戏实现2', '

迷宫介绍:

假设一个迷宫的矩阵图如下,其中用1表示通道,用0表示障碍物。入口在(1,1),出口在(8,8)。

0000000000

0110111010

0110111010

0111100110

0100011110

0111011110

0101110110

0100010010

0011111110

0000000000

为了表示迷宫,设置一个数组M*N的二维数组,其中每个元素表示一个方块的状态,为1时表示对应方块是通道,为0时表示对应方块是障碍物(不可走),或者相反。

求迷宫问题就是在一个指定的迷宫中求出从入口到出口的一条路径。在求解时采用“穷举法”,即从入口出发依次试探相邻的方块,一且找到一个可走的相邻方块就继续走下去,并记下所走的方位。两个方块有公共边称为相邻。

题目要求:

从以下难度等级中选择一个,用C/C++实现迷宫游戏,迷宫大小可输入。难度等级越大,得分越高。

1. 等级1:使用不超过10x10的二维数组模拟迷宫,输出行走路径或“无解”。

2. 等级2:使用不超过10x10的二维数组模拟迷宫,输出最短的行走路径或“无解”。

3. 等级3:使用不超过100x100的二维数组模拟迷宫,支持多出口,输出最短的行走路径或“无解”。

4. 等级4:使用不超过2x100x100的三维数组模拟两层楼迷宫,支持多出口和楼梯,输出最短的行走路径或“无解”。

5. 等级5:使用不超过2x100x100的三维数组模拟两层楼迷宫,支持多出口、楼梯和自定义楼梯距离,输出最短的行走路径或“无解”。

等级5的出口可参考以下范例输入:

2

1 3 5

0 10 39

表示有2个出口,分别在二楼的(3,5)和一楼的(10,39)坐标处

等级5的楼梯可参考以下范例输入:

2

8 9 3

15 27 2

表示有2个楼梯,位置(8,9)的楼梯可以从(0,8,9)处到达(1,8,9),距离为3;位置(15,27)的楼梯可以从(0,15,27)处到达(1,15,27),距离为2。

'); +INSERT INTO `problem` VALUES ('5', '1', '2', '迷宫游戏实现', '

迷宫介绍:

假设一个迷宫的矩阵图如下,其中用1表示通道,用0表示障碍物。入口在(1,1),出口在(8,8)。

0000000000

0110111010

0110111010

0111100110

0100011110

0111011110

0101110110

0100010010

0011111110

0000000000

为了表示迷宫,设置一个数组M*N的二维数组,其中每个元素表示一个方块的状态,为1时表示对应方块是通道,为0时表示对应方块是障碍物(不可走),或者相反。

求迷宫问题就是在一个指定的迷宫中求出从入口到出口的一条路径。在求解时采用“穷举法”,即从入口出发依次试探相邻的方块,一且找到一个可走的相邻方块就继续走下去,并记下所走的方位。两个方块有公共边称为相邻。

题目要求:

从以下难度等级中选择一个,用C/C++实现迷宫游戏,迷宫大小可输入。难度等级越大,得分越高。要求使用栈保存行走路径的信息,不能使用深度优先或广度优先等搜索算法。

1. 等级1:使用不超过10x10的二维数组模拟迷宫,输出行走路径或“无解”。

2. 等级2:使用不超过100x100的二维数组模拟迷宫,输出行走路径或“无解”。

'); + +-- ---------------------------- +-- Table structure for scoringrubric +-- ---------------------------- +DROP TABLE IF EXISTS `scoringrubric`; +CREATE TABLE `scoringrubric` ( + `id` int NOT NULL AUTO_INCREMENT, + `standardId` int DEFAULT NULL, + `lowerLimit` float DEFAULT NULL, + `upperLimit` float DEFAULT NULL, + `description` varchar(200) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of scoringrubric +-- ---------------------------- +INSERT INTO `scoringrubric` VALUES ('10', '25', '0', '100', '

使用AI编程助手的学生,需提交完整的交互过程记录,包括提问、AI回复和个人思考。将根据提问的技巧和思考的深度进行评分。不使用编程助手的学生,需提交设计思路文档。将根据设计的合理性、创新性和完整性进行评分。

'); +INSERT INTO `scoringrubric` VALUES ('14', '26', '0', '100', '

根据有无路径、路径的曲折程度等,提交至少5组不同的测试数据及其运行结果。测试数据应覆盖不同的迷宫布局和难度。测试数据的复杂性和完备性将影响得分。

'); +INSERT INTO `scoringrubric` VALUES ('15', '27', '0', '25', '

难度等级1:功能完善、无bug,得10分。

'); +INSERT INTO `scoringrubric` VALUES ('16', '27', '25', '50', '

难度等级2:功能完善、无bug,得20分。

'); +INSERT INTO `scoringrubric` VALUES ('29', '33', '0', '100', '

使用AI编程助手辅助编程,需提交完整的交互过程记录,包括提问、AI回复和个人思考。将根据提问的技巧和思考的深度进行评分。

'); +INSERT INTO `scoringrubric` VALUES ('31', '34', '0', '100', '

根据有无路径、路径的曲折程度等,提交至少5组不同的测试数据及其运行结果。测试数据应覆盖不同的迷宫布局和难度。测试数据的复杂性和完备性将影响得分。

'); +INSERT INTO `scoringrubric` VALUES ('50', '43', '0', '50', '

难度等级1:功能完善、无bug,得20分。

'); +INSERT INTO `scoringrubric` VALUES ('51', '43', '50', '100', '

难度等级2:功能完善、无bug,得40分。

'); +INSERT INTO `scoringrubric` VALUES ('54', '27', '50', '62.5', '

难度等级3:功能完善、无bug,得25分。

'); +INSERT INTO `scoringrubric` VALUES ('55', '27', '62.5', '75', '

难度等级4:功能完善、无bug,得30分。

'); +INSERT INTO `scoringrubric` VALUES ('56', '27', '75', '100', '

难度等级5:功能完善、无bug,得40分。

'); + +-- ---------------------------- +-- Table structure for scoringstandard +-- ---------------------------- +DROP TABLE IF EXISTS `scoringstandard`; +CREATE TABLE `scoringstandard` ( + `id` int NOT NULL AUTO_INCREMENT, + `problemId` int DEFAULT NULL, + `dimension` varchar(100) DEFAULT NULL, + `weight` float DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=50 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of scoringstandard +-- ---------------------------- +INSERT INTO `scoringstandard` VALUES ('25', '3', '交互过程或设计结果', '0.3'); +INSERT INTO `scoringstandard` VALUES ('26', '3', '测试结果', '0.3'); +INSERT INTO `scoringstandard` VALUES ('27', '3', '程序功能', '0.4'); +INSERT INTO `scoringstandard` VALUES ('33', '5', '交互过程', '0.3'); +INSERT INTO `scoringstandard` VALUES ('34', '5', '测试结果', '0.3'); +INSERT INTO `scoringstandard` VALUES ('43', '5', '程序功能', '0.4'); + +-- ---------------------------- +-- Table structure for studentclass +-- ---------------------------- +DROP TABLE IF EXISTS `studentclass`; +CREATE TABLE `studentclass` ( + `id` int NOT NULL AUTO_INCREMENT, + `userId` int NOT NULL, + `classId` int NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of studentclass +-- ---------------------------- +INSERT INTO `studentclass` VALUES ('7', '1', '3'); +INSERT INTO `studentclass` VALUES ('8', '2', '5'); +INSERT INTO `studentclass` VALUES ('13', '2', '8'); +INSERT INTO `studentclass` VALUES ('14', '3', '8'); +INSERT INTO `studentclass` VALUES ('15', '3', '5'); +INSERT INTO `studentclass` VALUES ('16', '19', '5'); +INSERT INTO `studentclass` VALUES ('17', '20', '9'); +INSERT INTO `studentclass` VALUES ('18', '21', '9'); +INSERT INTO `studentclass` VALUES ('19', '7085', '1'); +INSERT INTO `studentclass` VALUES ('21', '7084', '13'); +INSERT INTO `studentclass` VALUES ('22', '20', '5'); +INSERT INTO `studentclass` VALUES ('23', '7082', '3'); +INSERT INTO `studentclass` VALUES ('24', '7083', '3'); +INSERT INTO `studentclass` VALUES ('25', '7085', '3'); +INSERT INTO `studentclass` VALUES ('26', '7085', '13'); +INSERT INTO `studentclass` VALUES ('27', '7102', '13'); +INSERT INTO `studentclass` VALUES ('28', '6830', '13'); +INSERT INTO `studentclass` VALUES ('29', '21', '13'); +INSERT INTO `studentclass` VALUES ('30', '21', '1'); +INSERT INTO `studentclass` VALUES ('31', '7082', '1'); +INSERT INTO `studentclass` VALUES ('32', '7084', '1'); + +-- ---------------------------- +-- Table structure for submitreport +-- ---------------------------- +DROP TABLE IF EXISTS `submitreport`; +CREATE TABLE `submitreport` ( + `id` int NOT NULL AUTO_INCREMENT, + `problemId` int NOT NULL, + `studentId` int NOT NULL, + `adminuserId` int NOT NULL, + `readTime` datetime DEFAULT NULL, + `submissionTime` datetime DEFAULT NULL, + `submissionStatus` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, + `plagiarismStatus` varchar(10) DEFAULT NULL, + `attachment` varchar(200) DEFAULT NULL, + `autoscore` float DEFAULT NULL, + `autocomment` varchar(300) DEFAULT NULL, + `score` float DEFAULT NULL, + `comment` varchar(300) DEFAULT NULL, + `addTime` datetime DEFAULT NULL, + `simularity` float DEFAULT NULL, + `similardocs` varchar(200) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb3; + +-- ---------------------------- +-- Records of submitreport +-- ---------------------------- +INSERT INTO `submitreport` VALUES ('1', '5', '7082', '1', '2025-05-02 12:23:34', '2025-05-04 12:34:54', '待批阅', '已查重', 'zjy.docx', '90', null, '90', null, '2025-05-14 20:00:00', '0.342342', 'ly.docx'); +INSERT INTO `submitreport` VALUES ('2', '5', '21', '1', '2025-05-03 11:23:21', '2025-05-04 23:34:24', '已批阅', '已查重', 'ly.docx', '70', '基本达到要求但具体示例不够', '72', null, '2025-05-13 21:39:16', '0.56327', 'zjy.docx'); +INSERT INTO `submitreport` VALUES ('5', '3', '7082', '1', null, null, '未领取', null, null, null, null, null, null, '2025-05-13 11:06:23', '0', null); +INSERT INTO `submitreport` VALUES ('6', '5', '7085', '1', '2025-05-02 08:34:23', null, '已领取', null, null, null, null, null, null, null, null, null); + +-- ---------------------------- +-- Table structure for users +-- ---------------------------- +DROP TABLE IF EXISTS `users`; +CREATE TABLE `users` ( + `id` int NOT NULL AUTO_INCREMENT, + `username` varchar(50) NOT NULL, + `password` varchar(20) NOT NULL, + `studentNo` varchar(20) DEFAULT NULL, + `chineseName` varchar(30) DEFAULT NULL, + `banji` varchar(50) DEFAULT NULL, + `createDate` datetime NOT NULL, + `Email` varchar(50) DEFAULT NULL, + `solved` int DEFAULT '0', + `submit` int DEFAULT '0', + `answer` varchar(20) DEFAULT NULL, + `messageCondition` varchar(255) DEFAULT NULL, + `question` varchar(50) DEFAULT NULL, + `uuid` varchar(100) DEFAULT NULL, + `pwd` varchar(64) DEFAULT NULL, + PRIMARY KEY (`id`,`username`) +) ENGINE=InnoDB AUTO_INCREMENT=7105 DEFAULT CHARSET=gbk; + +-- ---------------------------- +-- Records of users +-- ---------------------------- +INSERT INTO `users` VALUES ('1', 'felix', '123456', '2131535', '李菲菲', '软件2班', '2015-08-10 10:27:48', '234567765@qq.com', '0', '0', '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('2', 'bing', '123456', '111330128', '郑彬彬', '软件1班', '2015-08-20 10:27:48', '', '0', '0', '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('3', 'peng', '1234567', '111330129', '马云鹏', '计算机1班', '2015-08-20 10:27:48', '', '0', '0', '', null, '', null, '8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414'); +INSERT INTO `users` VALUES ('19', 'zy', '123456', '141340108', '赵玥', '170928', '2015-10-11 20:45:19', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('20', 'zez', '123456', '1513000j2', '周恩子', '卓越软件1501', '2015-10-11 20:45:19', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('21', 'ly', '123456', '151320101', '刘颖', '卓越软件1501', '2015-10-11 20:45:19', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('6830', 'jyc', '123456', '20630325', '金宇宸', '202101', '2023-06-30 14:42:10', '2845141619@qq.com', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('7082', 'zjy', '123456', '231310507', '张嘉仪', '计算机类专业2023级秋季5班', '2023-09-28 15:26:52', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('7083', 'zyx', '123456', '231310508', '赵芸溪', '计算机类2305', '2023-09-28 15:28:28', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('7084', 'czx', '123456', '231310509', '蔡兆炫', '计算机类2305', '2023-09-30 22:30:44', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('7085', 'ckl', '123456', '231310510', '陈坤龙', '计算机类2305', '2023-09-28 15:30:28', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); +INSERT INTO `users` VALUES ('7102', 'yxy', '123456', '231310531', '鄢欣云', '计算机类2305', '2023-09-28 15:44:59', '', null, null, '', null, '', null, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'); diff --git a/docs/自动评分系统需求说明书.md b/docs/自动评分系统需求说明书.md new file mode 100644 index 0000000..9d9eff4 --- /dev/null +++ b/docs/自动评分系统需求说明书.md @@ -0,0 +1,1041 @@ +# 自动评分系统需求说明书 + +| 项 | 内容 | +| --- | --- | +| 项目名称 | 自动评分系统(AES, Auto Essay/Experiment Scoring) | +| 文档类型 | 产品需求说明书 / 软件需求规格说明(PRD + SRS) | +| 当前版本 | V1.0 | +| 状态 | 待导师确认 | +| 编写日期 | 2026-09-18 | +| 适用范围 | 当前仓库 `AUTO_SCORE` 的下一阶段实现 | +| 主要读者 | 导师、开发者 | + +--- + +## 修订记录 + +| 版本 | 日期 | 说明 | +| --- | --- | --- | +| V1.0 | 2026-09-18 | 依据导师需求讨论会(`docs/需求说明.mp4`)、语音转写、速记文档与现有 Demo 代码整理首版完整需求 | + +--- + +## 目录 + +1. [文档说明](#1-文档说明) +2. [问题陈述与产品概述](#2-问题陈述与产品概述) +3. [现状 Demo 与目标差距](#3-现状-demo-与目标差距) +4. [用户角色与核心流程](#4-用户角色与核心流程) +5. [信息架构与界面需求](#5-信息架构与界面需求) +6. [用户故事](#6-用户故事) +7. [功能需求](#7-功能需求) +8. [数据需求](#8-数据需求) +9. [非功能需求](#9-非功能需求) +10. [验收标准](#10-验收标准) +11. [分期计划](#11-分期计划) +12. [待确认问题](#12-待确认问题) +13. [附录](#13-附录) + +--- + +## 1. 文档说明 + +### 1.1 目的 + +本文档把导师讨论会上已经拍板的产品形态、交互规则、数据约束和实现边界写成一份可开发、可验收的需求说明,作为后续改 Demo、拆任务和联调的依据。 + +### 1.2 范围 + +本系统面向高校实验课 / 大作业场景:教师布置**一份作业对应一道题**,学生提交实验报告(及可选压缩包附件),系统用大模型按评分标准异步批阅,教师再审核或改分。学生最终看到的成绩以教师结果优先。 + +范围内包括: + +- 学生端:课程列表、作业列表、作业详情、提交与重传申请、成绩展示 +- 教师端:作业库、出题与评分标准生成、发布、已发布作业管理、批阅、打回、加时、导出 +- 独立批阅进程:从数据库拉取待批记录,读取磁盘上的实验报告文本,调用大模型写回分项成绩 +- 文件校验、上传次数控制、导出包生命周期 + +范围外见 [2.4 非目标](#24-目标与非目标)。 + +### 1.3 需求来源优先级 + +发生冲突时按以下顺序取舍: + +1. 导师在讨论会中的明确决定(转写中标记为 `[1]`) +2. 速记文档 `docs/自动评分系统/自动评分系统.md` +3. 现有 Demo 已实现且本次未要求删除的能力(课程、班级、账号、登录等底座) +4. 开发侧合理推断(必须写入「待确认问题」,不得当成已拍板需求) + +转写约定:`[0]` 为学生(缠缍),`[1]` 为导师,`[2]`/`[3]`/`[4]` 为附和、口误或环境音,不作为需求依据。 + +### 1.4 参考资料 + +| 资料 | 位置 / 说明 | +| --- | --- | +| 需求讨论录像 | `docs/需求说明.mp4` | +| 语音转写 | `docs/通用语音识别_需求说明.mp4 (1).txt` | +| 会议速记 | `docs/自动评分系统/自动评分系统.md` | +| 现有库结构 | `aes.sql` | +| 后端 Demo | `AES/`(Spring + Hibernate,端口 8082) | +| 前端 Demo | `AES-front/`(Vue 3 + Vite) | +| 现有评分脚本 | `original.py`(按维度调用大模型) | +| 交互参照 | 教学平台作业发布/批阅页、OJ 作业列表与评测机、知网查重的「一次上传、再传需申请」 | +| 文档写法参照 | ISO/IEC/IEEE 29148 需求条目可验证原则;项目内 `.cursor/skills/write-spec`、`prd-template`、`meeting-to-spec` | + +### 1.5 术语与缩写 + +| 术语 | 含义 | +| --- | --- | +| 作业 / 题目 | 本系统一份作业只含一道题,不再拆「第 1 题、第 2 题」 | +| 作业库 | 已出题但尚未发布到班级的题目集合 | +| 已发布作业 | 已指定班级/学生、截止时间后对学生可见的作业 | +| 实验报告 | 学生提交的可读文档(docx / doc / pdf,或仅含这些文件的 zip) | +| 附件 | 与实验报告分开的**一个**压缩包,放代码等材料 | +| 评分标准 | 发给大模型的结构化评分依据,含维度、分档与注意事项 | +| 维度 | 评分标准中的一个评分项,如「团队协作」。单份作业最多 10 个 | +| AI 成绩 | 批阅机根据评分标准算出的分项分与评语,不可被教师覆盖 | +| 教师成绩 | 教师审核通过或修改后另存的分项分与评语 | +| 打回 | 教师驳回本次提交,学生需重新申请/重新提交后才能再进入批阅 | +| 补交 | 过了正式截止时间后,在补交截止时间前仍允许提交 | +| 加时 | 教师给指定未交学生延长可提交时间 | +| 申请重传 | 学生已成功提交后,不能直接再传,需教师同意后才能替换文件 | +| 批阅机 | 独立于 Web 服务的后台进程,类似 OJ 评测机 | +| P0 / P1 / P2 | 必须有 / 应尽快有 / 本阶段不做但设计上不要堵死 | + +--- + +## 2. 问题陈述与产品概述 + +### 2.1 问题陈述 + +实验课大作业以实验报告为主,一份作业往往只有一道综合题,却需要按多个维度给分。教师手工拆维度、写分档、逐份批改成本很高;若让学生反复上传,每次调用大模型都会产生费用,且超长报告、超大附件会把批阅质量打下去。 + +当前 Demo 已经能登录、建课、出题、提交、调用大模型出总分,但学生入口不像课程列表、作业状态不够细、评分标准仍靠手工建维度表、AI 分与教师分未按「分项另存」设计、缺少申请重传、补交截止展示、独立批阅机和可靠的附件导出。不补齐这些,系统无法按导师的实际上课方式使用。 + +### 2.2 产品定位 + +本系统不是通用考试平台,也不是多题试卷系统。它是: + +- 一门课程下的**大作业收发与 AI 辅助批阅工具** +- 一份作业 = 一道题 + 一份评分标准 + 实验报告(及可选压缩包) +- 批阅分两步:**大模型先评,教师再确认或改分** +- 成绩展示以教师结果优先;AI 结果始终保留,便于对照 + +参照对象: + +- 作业列表、独立评测进程 → OJ +- 一次上传、再传需申请 → 知网查重 +- 发布对象、已交/未交/待批、批阅页、导出 → 现有教学平台作业模块 + +### 2.3 产品功能总览 + +```text +学生:登录 → 课程列表 → 某门课的作业列表 → 作业详情(描述 / 上传 / 成绩) +教师:登录 → 课程列表 → 作业库(出题)或 已发布作业 + 出题:标题 + 描述 + 评分标准(可自动生成) + 发布:班级/个人 + 截止 + 是否补交 + 批阅:看 AI 分项结果 → 审核通过 或 修改后保存 +批阅机:轮询待批记录 → 读 upload 中的报告文本 → 调大模型 → 写回 AI 分项成绩 +``` + +### 2.4 目标与非目标 + +**目标(本阶段做成后应成立)** + +- G1. 学生能按「课程 → 作业列表 → 作业详情」完成查看、提交、看分,并在列表上区分五种作业状态。 +- G2. 教师能用「简单要求 + 题目描述」生成可入库的评分标准,手工修改后发布到班级。 +- G3. 每份提交保留 AI 分项成绩与教师分项成绩两套字段;学生看到的是「教师优先」。 +- G4. 实验报告和附件在上传时就被格式、大小、字数、可读性拦住,避免再出现几百页、几百兆的无效提交。 +- G5. 学生不能无限次触发批阅;已成功提交后需「申请重传 + 教师同意」。 +- G6. 批阅不阻塞提交接口,由独立进程异步完成,学生需等待一段时间再查看结果。 + +**非目标(明确不做)** + +| 不做 | 原因(来自会议) | +| --- | --- | +| 一份作业多道题、按人/按题两种批阅模式 | 本课一份作业就是一道题 | +| 教师批量打分 | 导师明确「现在先不做」 | +| 未交名单里的「设为已交」「查看」 | 没交就没有可看内容 | +| 作业统计页 | 导师认为无所谓、不需要 | +| 发布时站内通知 | 导师当前没有通知需求 | +| 把图片发给大模型 | 现在只发文字 | +| 提交后立刻出分 | 明确对标知网:提交后等一段时间 | +| 学生随意多次上传替换 | 每次批阅都花钱 | +| 评分维度超过 10 个 | 宽表字段有上限,超过则拒绝保存 | +| 以大模型返回的总分为准 | 分项加总才作为总分,防止加减不一致被学生质疑 | +| 管理员审核重传(本阶段) | 先由任课教师同意;人多了以后再说 | + +--- + +## 3. 现状 Demo 与目标差距 + +现有工程是可用的教学 Demo,不是最终产品。底座(登录、课程、班级、学生、助教、作业库/发布骨架)可复用;下列差距是本需求的改造重点。 + +| 模块 | 现有 Demo | 目标 | +| --- | --- | --- | +| 学生首页 | 「点击进入作业 / 加入班级 / 帮助」,作业列表不按课程分层 | 先课程列表,点进一门课才是作业列表 | +| 学生作业列表 | 作业名、描述、开始/结束时间、单一状态、分页 | 表格展示截止时间、状态(五种)、分数;一门课作业数量通常 ≤ 20,可不分页 | +| 作业状态 | `未领取 / 已领取 / 待批阅 / 已批阅`,另有查重标红 | `未交 / 待批阅 / 分数(AI) / 分数(教师) / 打回` | +| 作业详情 | 左:描述+上传;右:教师评语;上传在页面下方 | 描述置顶;右侧放附件区;分数在附件下方;教师端详情不再重复题目描述 | +| 提交文件 | 单文件,`txt/doc/docx/pdf`,限制 1 个 | 实验报告 + 可选 1 个 zip;系统规定格式;校验可读、字数、大小;是否必交由教师勾选 | +| 再次上传 | 上传即覆盖,无次数控制 | 默认可交 1 次;再传需申请,教师同意后才能替换 | +| 补交 | `postproblem.allow` 仅 0/1,无补交截止时间,学生端不展示 | 允许补交时必须有补交截止;列表和详情都要显示 | +| 评分标准 | `scoringstandard`(维度+权重)+ `scoringrubric`(分档),教师逐条建 | 教师写简要要求,大模型生成带分档的标准;教师可改;入库前校验结构 | +| AI 成绩存储 | `autoscore` 一个总分 + `autocomment` 拼接评语 | 总分 = 各维度分数之和;每维分数+评语分字段保存,最多 10 维 | +| 教师批阅 | 详情仍显示题目;教师分会写 `score/comment`,但不是分项复制工作流 | 左 AI 右教师;「修改」复制到右侧;「审核通过」不改分;两套字段互不覆盖 | +| 批阅触发 | Web 接口 `/autoscore` 同步调 Python | 独立批阅机轮询数据库,类似 OJ 评测机 | +| 导出附件 | 前端按钮已注释 | 分「导出实验报告」「导出附件」;按 `学号-姓名` 打包;超大则分卷;下载后或 1 天后删除 | +| 仓库 | `.gitignore` 几乎为空,存在二进制和本地库风险 | 二进制不进 Git;库结构/文档放 `docs/` | + +现有 Demo 中**本阶段默认保留**的能力:教师/学生/助教登录与账号、课程与班级、作业库与发布骨架、文件落在 `upload/` 而不是数据库、查重相关字段(会议未要求删除,也未作为本轮重点,见待确认问题 Q5)。 + +--- + +## 4. 用户角色与核心流程 + +### 4.1 用户特征 + +| 角色 | 说明 | +| --- | --- | +| 学生 | 查看自己所选课程的作业,上传报告,查看状态与成绩 | +| 教师 | 出题、生成/修改评分标准、发布、批阅、打回、加时、导出。当前导师同时是教师和管理员 | +| 助教 | Demo 已有班级助教。本轮会议未重定义,暂沿用现有权限,不新增需求 | +| 管理员 | 账号与系统维护。重传审批本阶段不交给管理员 | + +### 4.2 学生主流程 + +```text +进入系统 + → 课程列表 + → 某课程的作业列表(看到截止时间、状态、分数) + → 作业详情 + 描述(置顶) + 右侧:实验报告 / 附件 上传与下载 + 附件下方:当前成绩与评语(教师优先,否则 AI) + → 首次提交成功后进入「待批阅」 + → 批阅机完成后变为「分数(AI)」 + → 教师审核/改分后变为「分数(教师)」 + → 若被打回:状态为「打回」,需申请重传并获批后才能再交 +``` + +### 4.3 教师主流程 + +```text +课程列表 → 进入课程 + ├─ 作业库:新建 / 编辑题目(标题、描述、评分标准) + │ 评分标准可自动生成 → 教师修改 → 校验格式 → 入库 + └─ 已发布作业:发布(班级/个人、截止、补交) + → 作业汇总(已交 / 待批 / 未交) + → 已交名单:批阅 / 打回 / 导出成绩 / 导出文件 + → 未交名单:加时 / 批量加时 / 导出未交名单 + → 重传申请:同意后学生可再传一次 +``` + +### 4.4 批阅机流程 + +```text +循环: + 取出状态=待批阅 且尚未写入 AI 成绩的提交 + 从 upload/ 读取实验报告,抽出文字(忽略图片) + 与该题评分标准一并送入大模型 + 解析各维度 score / comment + 校验维度数量 ≤ 10 + 总分 = Σ 维度分数(不用模型返回的 total) + 写入 AI 字段,学生端显示「分数(AI)」 +``` + +学生提交接口**只负责收文件和建待批记录**,不在请求内同步完成大模型调用。 + +--- + +## 5. 信息架构与界面需求 + +### 5.1 学生端页面 + +#### UI-001 课程列表 + +登录后首先看到课程列表,交互对齐导师展示的课程卡片/列表,而不是现在的「点击进入作业」首页文案。点击一门课程进入该课作业列表。课程卡片上不需要再堆 Demo 首页那大段说明。 + +#### UI-002 作业列表 + +做成类似 OJ 的表格。建议列: + +| 列 | 内容 | +| --- | --- | +| 作业名称 | 标题 | +| 截止时间 | 正式结束时间 | +| 补交 | 不允许补交 / 补交截止时间(若允许) | +| 状态 / 分数 | 见 5.3 状态机 | +| 操作 | 进入详情 | + +一门课大作业通常不超过约 20 个,**可以不分页**,一页显示完。若后续作业很多,再加分页,但不是本阶段必须。 + +不要在列表里放很长的作业描述正文。列表信息要足够让学生判断:有没有交、截止何时、现在几分、是 AI 还是教师。 + +#### UI-003 作业详情(学生) + +页面结构(导师指定): + +1. **顶部**:作业标题、截止/补交信息、当前状态 +2. **上部主体**:作业描述(学生端必须保留描述,因为要知道做什么) +3. **右侧**:附件区(实验报告 + 压缩包),可下载已传文件 +4. **附件下方**:分数与评语 + +不需要「第 1 题、第 2 题」题号区。右侧不再放与附件无关的模块。 + +上传控件规则见 FR-S 系列。分数展示规则见 FR-S-007。 + +### 5.2 教师端页面 + +#### UI-010 课程列表 + +教师端进入后也是课程列表,风格可与学生端一致。点进一门课后,分为: + +- **作业库** +- **已发布作业** + +#### UI-011 新建 / 编辑作业(作业库) + +字段: + +1. 作业标题 +2. 作业描述(富文本) +3. 评分标准(富文本或结构化编辑区,支持自动生成) +4. 提交约束(见 FR-T-010) + +评分标准区旁边可放「?」帮助,只展示参考示例给教师看;真正发给模型的阶层结构放在系统提示词里,不必全部摊在编辑器上。 + +保存失败时,若结构不合格,**直接告诉教师应按什么格式写**,而不是静默入库。 + +#### UI-012 发布作业 + +- 发布对象:班级多选;也可发到个人;支持全选/取消全选、按姓名搜索 +- 结束时间(正式截止) +- 是否允许补交;允许则必须填补交截止时间 +- 本阶段不做站内通知,也不做「允许重做几次」(改由申请重传机制控制) + +#### UI-013 已发布作业列表 + +表格至少显示: + +- 作业名称、正式截止时间 +- 是否允许补交、补交截止时间(允许时必显示,否则教师自己也记不清) +- 已交人数、待批人数、未交人数 +- 班级筛选、状态筛选(未开始 / 进行中 / 已结束)、标题搜索 + +#### UI-014 提交名单(已交 / 未交) + +**已交表**列建议:学号、姓名、班级、提交时间、提交 IP、状态、批阅人(`AI` 或教师姓名)、成绩、操作(批阅、打回)。支持按成绩等列排序。顶部汇总:全部人数、已交、未交。 + +支持按班级筛选。可多选后: + +- 批量打回 +- 导出成绩 +- 导出实验报告 +- 导出附件 + +不做批量打分,不做按人/按题切换。 + +**未交表**:加时、批量加时、导出未交名单。不提供「设为已交」,不提供「查看」。 + +#### UI-015 批阅详情 + +进入后**不要再展示题目描述**。教师此页只做一件事:看 AI 结果,决定确认还是改。 + +```text +左:AI 批阅结果(只读) 右:教师打分与评语 + 总分(分项之和) 总分(分项之和) + 维度1 分数 / 评语 维度1 分数 / 评语 + 维度2 分数 / 评语 维度2 ... + ... +按钮:审核通过 | 修改 | 保存 | 打回 +``` + +- **审核通过**:不改分,把当前 AI 结果确认为教师侧成绩(另存,不覆盖 AI 字段),学生状态改为「分数(教师)」 +- **修改**:把左侧分数和评语复制到右侧,教师改完点保存 +- **保存**:只写教师字段 +- 教师未操作时,学生看到 AI;教师操作后,学生只看到教师结果 + +### 5.3 作业状态机 + +对学生可见的五种状态(导师最终用「未交」而不是「未完成」): + +| 状态 | 含义 | 列表展示 | +| --- | --- | --- | +| 未交 | 在可交期内(含加时/补交)尚未成功提交 | 文案「未交」 | +| 待批阅 | 已成功提交,批阅机尚未写出 AI 成绩 | 文案「待批阅」 | +| 分数(AI) | AI 已出分,教师尚未审核/改分 | 如 `95(AI)` | +| 分数(教师) | 教师已审核通过或已保存改分 | 如 `98(教师)` | +| 打回 | 教师打回本次提交 | 文案「打回」 | + +「未交」和「打回」必须分开,不能合成一个「未完成」。 + +建议内部流转: + +```text +未交 --提交成功--> 待批阅 --批阅机完成--> 分数(AI) +分数(AI) --教师审核通过或保存改分--> 分数(教师) +分数(AI) 或 分数(教师) --打回--> 打回 +打回 --教师同意重传且学生再次提交成功--> 待批阅 +未交 --教师加时/仍在补交窗--> 仍为未交,但可提交 +过了正式截止且不允许补交(或过了补交截止)且未提交 --> 仍显示未交,但不可提交 +``` + +--- + +## 6. 用户故事 + +### US-001 按课程查看作业 + +**描述:** 作为学生,我想先看到自己的课程,再进入某门课的作业表,以便只关心当前这门课的大作业。 + +**验收:** + +- [ ] 登录后落地页是课程列表,而不是直接铺开全部作业 +- [ ] 点入课程后只显示该课作业 +- [ ] 作业表能看到截止时间、补交信息、状态/分数 + +### US-002 提交实验报告并立刻知道有没有交上 + +**描述:** 作为学生,我想在作业详情里看清要求、上传报告和附件,并确认文件已经保存且可下载。 + +**验收:** + +- [ ] 描述在页面上部可见 +- [ ] 上传区在右侧,已传文件可下载 +- [ ] 不满足格式/大小/字数/可读性时提交失败,并给出具体原因 +- [ ] 必交项未上传时不能提交成功 + +### US-003 控制重复批阅成本 + +**描述:** 作为教师,我希望学生不能每改几个字就重新上传一次,以免反复调用大模型产生费用。 + +**验收:** + +- [ ] 成功提交后,上传入口变为不可用(或仅显示「申请重传」) +- [ ] 学生提交申请后,教师能在待办/名单中看到 +- [ ] 教师同意前,学生不能再次上传 +- [ ] 教师同意后,学生可再上传并再次进入待批阅 + +### US-004 等待异步出分 + +**描述:** 作为学生,我提交后不必立刻拿到分数,但过一段时间应能看到 AI 分,并知道这是 AI 给的。 + +**验收:** + +- [ ] 提交成功后状态为「待批阅」,不阻塞在提交按钮上长时间转圈调用模型 +- [ ] AI 完成后列表出现 `分数(AI)` +- [ ] 教师确认后变为 `分数(教师)`,数值以教师为准 + +### US-005 用简要要求生成评分标准 + +**描述:** 作为教师,我不想手工写「9–10 分什么样、7–8 分什么样」,只想写题目和几条关键要求,让模型生成可修改的标准。 + +**验收:** + +- [ ] 教师输入题目描述 + 简要评分要求后可一键生成 +- [ ] 生成结果出现在评分标准框中,教师可改 +- [ ] 超过 10 个维度时保存被拒绝并提示 +- [ ] 格式不符合入库结构时,提示应采用的格式,不写入数据库 + +### US-006 对照 AI 结果做人工审核 + +**描述:** 作为教师,我想左右对照 AI 分项结果,一键复制后修改,或直接审核通过,并且不丢掉 AI 原始分。 + +**验收:** + +- [ ] 批阅页不显示题目正文 +- [ ] 左侧只读 AI 分项,右侧教师可编辑 +- [ ] 「修改」复制左侧到右侧 +- [ ] 「审核通过」不改分数,状态变为教师 +- [ ] 数据库中 AI 字段仍在 + +### US-007 处理未交和打回 + +**描述:** 作为教师,我想给个别学生加时,或把不合格作业打回,并导出未交名单。 + +**验收:** + +- [ ] 未交名单可单人加时、批量加时 +- [ ] 已交名单可打回、批量打回 +- [ ] 可导出未交名单 +- [ ] 学生端能区分未交与打回 + +### US-008 按学号姓名导出文件 + +**描述:** 作为教师,我想分别导出实验报告和附件,文件按 `学号-姓名` 命名,并在导出很大时拆包。 + +**验收:** + +- [ ] 两个独立导出入口 +- [ ] zip 内条目名为 `学号-姓名` + 原扩展名(或内层仍为 zip) +- [ ] 超过约定体积则拆成多份 +- [ ] 完成后提示「请在某时之前下载」;下载完成或到期后删除临时包 + +--- + +## 7. 功能需求 + +优先级:P0 本阶段必须交付;P1 明显提升体验,时间允许应做;P2 明确留到以后。 + +### 7.1 学生端 + +**FR-S-001 课程列表入口** + +- Description: The system shall 在学生登录后展示其已加入的课程列表,点击课程后进入该课程作业列表。 +- Priority: P0 +- Source: 会议 + +**FR-S-002 作业列表字段** + +- Description: The system shall 在作业列表中展示作业名称、截止时间、补交信息、状态/分数。不得只显示作业名而把截止与是否已交藏进详情。 +- Priority: P0 + +**FR-S-003 五种状态展示** + +- Description: The system shall 按 5.3 展示状态。AI 分与教师分不得混成一个「已完成」。 +- Priority: P0 + +**FR-S-004 作业详情布局** + +- Description: The system shall 将作业描述置于详情页上部,将实验报告与附件上传/下载放在右侧,将分数与评语放在附件区域下方。学生端必须显示作业描述。 +- Priority: P0 + +**FR-S-005 首次提交** + +- Description: The system shall 在「未过正式截止」或「允许补交且未过补交截止」或「该生仍在加时窗口」时,允许尚未成功提交的学生上传。 +- Priority: P0 + +**FR-S-006 申请重传** + +- Description: The system shall 在学生已经成功提交之后,禁止直接再次上传。页面提供「申请重传」。教师同意后,该生获得一次新的上传资格。 +- Priority: P0 +- Note: 会议先定「教师同意即可」。不要做成随时覆盖保存。 + +**FR-S-007 成绩与评语优先级** + +- Description: The system shall 在教师成绩存在时向学生展示教师的总分、分项分和评语;否则展示 AI 的对应内容。不得把两套结果混成一段无法区分来源的文本。 +- Priority: P0 + +**FR-S-008 已传文件下载** + +- Description: The system shall 允许学生下载自己已成功保存的实验报告和附件。桌面端点击即可下载;需同时保证移动端也能完成下载(会议提到有同学反馈手机上看不到/不能下)。 +- Priority: P0 + +**FR-S-009 提交后等待** + +- Description: The system shall 在提交成功后将状态置为「待批阅」,不保证实时出分。可提示「批阅需要一段时间,请稍后查看」。 +- Priority: P0 + +### 7.2 教师出题与评分标准 + +**FR-T-001 作业库与已发布分离** + +- Description: The system shall 将「未发布题目」放在作业库,「已发布实例」放在已发布列表。新建作业默认进入作业库,不自动对学生可见。 +- Priority: P0 + +**FR-T-002 出题必填内容** + +- Description: The system shall 保存作业时同时持久化:标题、题目描述、发给大模型的评分标准、提交约束。缺评分标准不得发布。 +- Priority: P0 + +**FR-T-003 评分标准自动生成** + +- Description: The system shall 支持教师点击生成评分标准。发送给大模型的信息固定为三部分: + + 1. 教师写的题目描述 + 2. 教师写的简要评分要求(例如「团队合作 10 分,需有 git 提交记录且覆盖三个时间点」) + 3. 系统内置的参考阶层结构 / 输出格式(放在 system prompt,不要求教师手写 JSON) + +- Priority: P0 +- Note: 会议现场把整篇参考文档塞进提示词后,模型会误当成要重写参考文。提示词必须标明「以下是格式参考,不是题目本身」。 + +**FR-T-004 教师可编辑生成结果** + +- Description: The system shall 允许教师在入库前和入库后修改评分标准正文(例如补上「个人完成且未用 agent 模拟成员最多 2 分」这类模型没写的规则)。 +- Priority: P0 + +**FR-T-005 结构校验与维度上限** + +- Description: The system shall 在保存评分标准时解析出维度列表。维度数必须为 1–10;超过 10 个则拒绝保存并提示不允许超过 10 个维度。解析失败则提示应采用的撰写格式(除「注意事项」是否展示给教师外,格式主体都应说明清楚)。 +- Priority: P0 + +**FR-T-006 生成结果必须可入库** + +- Description: The system shall 保证最终写入数据库的是结构化字段(维度名、满分、分档说明等),而不是只能给人看、不能给批阅机用的自由文本。教师看到的编辑稿可以是 Markdown,但保存前必须能解析。 +- Priority: P0 + +**FR-T-010 提交约束(出题时配置)** + +教师可为每份作业配置: + +| 配置项 | 规则 | 谁决定 | +| --- | --- | --- | +| 实验报告是否必交 | 勾选则不交报告不能提交 | 教师 | +| 附件是否必交 | 勾选则不交 zip 不能提交 | 教师 | +| 报告最少字数 | 按「字」展示给师生;后台按字符统计 | 教师 | +| 报告最多字数 | 同上,用于拦住把完整 AI 对话+代码贴成几百页的报告 | 教师 | +| 报告大小上限 | 会议示例 5MB | 教师可配,系统给默认值 | +| 附件大小上限 | 会议示例 10MB | 教师可配,系统给默认值 | + +以下**由系统规定,不开放给教师选**: + +- 实验报告允许:`docx`、`doc`、`pdf`;或 `zip`,但 zip 内只能包含这三种文档 +- 附件允许:一个 `zip` +- 图片不送给大模型,字数统计也不把图片算进去 + +**FR-T-011 上传校验失败要说人话** + +- Description: The system shall 在校验失败时拒绝保存,并返回可理解原因,例如:找不到 docx/doc/pdf、文档打不开、zip 内含不允许的文件、超过大小、少于最少字数、超过最多字数。 +- Priority: P0 +- Note: 导师会提供已有的文档/zip 读取脚本;也可用现有能力重写,但行为要一致。 + +### 7.3 发布、补交、加时 + +**FR-P-001 发布对象** + +- Description: The system shall 支持按班级发布,并支持发给班级中的指定学生;提供全选、取消全选、按姓名搜索。 +- Priority: P0 + +**FR-P-002 补交窗口** + +- Description: The system shall 在允许补交时要求设置补交截止时间。过了补交截止后,未获加时的学生不能再交。 +- Priority: P0 + +**FR-P-003 补交信息展示** + +- Description: The system shall 在教师已发布列表、学生作业列表、学生作业详情中展示是否允许补交及补交截止时间。仅写在「修改设置」里但列表不可见,视为不满足。 +- Priority: P0 + +**FR-P-004 加时** + +- Description: The system shall 允许教师对未交学生单人加时和批量加时。加时只延长该生可提交窗口,不改变整份作业对其他学生的截止时间。 +- Priority: P0 + +### 7.4 教师批阅 + +**FR-R-001 批阅页信息** + +- Description: The system shall 在批阅详情展示学生学号、姓名、班级、可下载的实验报告与附件、AI 分项结果、教师分项编辑区。不展示题目描述正文。 +- Priority: P0 + +**FR-R-002 AI 与教师字段隔离** + +- Description: The system shall 将 AI 的总分、各维分数、各维评语与教师的对应字段分开存储。教师保存不得覆盖 AI 字段。 +- Priority: P0 + +**FR-R-003 审核通过与修改** + +- Description: The system shall 提供「审核通过」:把 AI 结果复制为教师结果(若教师侧尚空)并切换学生可见状态为教师,分数数值不变。提供「修改」:把 AI 结果填入教师编辑区供改。提供「保存」:只提交教师编辑区。 +- Priority: P0 + +**FR-R-004 打回** + +- Description: The system shall 支持单人打回与已交名单上的批量打回。打回后学生状态为「打回」,在获得重传许可前不能再交。 +- Priority: P0 + +**FR-R-005 名单能力** + +- Description: The system shall 在已交名单支持排序、班级筛选、导出成绩、分别导出实验报告和附件。不做批量打分。 +- Priority: P0 + +**FR-R-006 未交名单** + +- Description: The system shall 支持导出未交名单,以及加时。不提供设为已交、不提供查看空提交。 +- Priority: P0 + +**FR-R-007 重传审批** + +- Description: The system shall 让教师看到学生的重传申请并同意或拒绝。同意后该生可再上传一次。 +- Priority: P0 + +### 7.5 批阅机与大模型 + +**FR-J-001 独立进程** + +- Description: The system shall 将自动批阅做成独立运行的程序/服务,从数据库逐条取待批记录,而不是在学生提交的 HTTP 请求里同步打完分。行为对齐 OJ 评测机。 +- Priority: P0 + +**FR-J-002 输入** + +- Description: The system shall 只把实验报告抽取的文字,以及该题评分标准,发给大模型。压缩包附件默认不作为批阅输入(除非后续另开需求)。图片忽略。 +- Priority: P0 + +**FR-J-003 输出与总分** + +- Description: The system shall 解析每个维度的 score 与 comment。总分必须等于各维度分数之和,即使模型另外返回了 total 也不得采用。 +- Priority: P0 +- Rationale: 分项偶然不准,学生最多质疑某一维;若分项相加不等于总分,会被认为系统不可用。 + +**FR-J-004 结构化落库** + +- Description: The system shall 将总体评语、各维分数、各维评语写入固定字段(宽表,最多 10 维),而不是只拼一句 `autocomment`。 +- Priority: P0 + +**FR-J-005 失败可重试** + +- Description: The system shall 在模型失败、解析失败、文件读失败时保留待批阅或标记失败原因,不得写成一个无法解释的 0 分成功结果。失败记录应能再次进入队列。 +- Priority: P1 + +**FR-J-006 提示词职责分离** + +- Description: The system shall 将系统提示(格式、阶层结构、禁止编造维度)与用户提示(题目+教师要求+报告正文)分开,避免模型把参考格式当成新题目。 +- Priority: P0 + +### 7.6 导出与临时文件 + +**FR-E-001 导出实验报告 / 导出附件** + +- Description: The system shall 提供两个导出动作。每个学生在包内的文件夹或文件主名为 `学号-姓名`。若学生交的是 docx,则包内为该文档;若交的是 zip,则包内仍是 zip。 +- Priority: P0 + +**FR-E-002 分卷** + +- Description: The system shall 在导出包过大时拆成多份。单份上限由实现选定,会议建议 500MB 或 1GB,需在实现时写进配置并在界面提示。 +- Priority: P0 + +**FR-E-003 临时包生命周期** + +- Description: The system shall 在导出完成后提示「请及时下载,将保留到 YYYY-MM-DD HH:mm」。文件被成功下载后删除该临时包;若一直不下载,则在保留期结束后由定时任务删除。建议默认保留 1 天。 +- Priority: P0 +- Note: 不要做成教学平台那种长期可重复下载的导出历史,以免占磁盘。 + +**FR-E-004 导出成绩 / 未交名单** + +- Description: The system shall 支持导出已交成绩表和未交名单。格式可用 xlsx。 +- Priority: P0 + +### 7.7 仓库与文档约定 + +**FR-D-001 不把无用二进制推进 Git** + +- Description: The repository shall 排除构建产物、`node_modules`、学生作业、超大媒体、本地密钥。导师要求上传前删掉不必要的二进制以节省空间。 +- Priority: P0 + +**FR-D-002 数据库脚本放文档目录** + +- Description: The repository shall 将库结构/示例数据作为文档放在 `docs/`(或导师指定的 dock/docs 目录),而不是把运行中的数据库文件直接塞进仓库根。 +- Priority: P0 +- Source: 会议结尾「数据库也上传,放到 docs 目录当文档」 + +--- + +## 8. 数据需求 + +### 8.1 设计原则 + +1. 文件本体放磁盘 `upload/`(或等价目录),数据库只存路径、校验信息和批阅结果。 +2. 评分结果用**宽表分项字段**,不用「一行一个字段名」的 EAV 表。导师认可宽表查询更快;维度上限 10 是为此服务的。 +3. AI 与教师两套结果并存。 + +### 8.2 现有表(可复用底座) + +`aes.sql` 中已有:`adminusers`、`users`、`course`、`class`、`studentclass`、`assistantclass`、`problem`、`postproblem`、`scoringstandard`、`scoringrubric`、`submitreport`。 + +`submitreport` 现有字段包括:`attachment`、`autoscore`、`autocomment`、`score`、`comment`、`submissionStatus`、`addTime`、查重相关字段等。这套结构**不够**表达:双文件、分项成绩、补交截止、重传申请、打回与未交的区分。 + +### 8.3 需要演进的逻辑数据 + +下列为逻辑模型,不强制一次迁移完成,但 P0 功能必须能存下这些信息。 + +**作业(题目,作业库)** + +| 字段 | 说明 | +| --- | --- | +| id, courseId, teacherId | 归属 | +| title, description | 标题与富文本描述 | +| rubricText | 教师可见的评分标准文稿 | +| rubricParsed | 解析后的维度数组(JSON 可接受) | +| reportRequired, attachmentRequired | 是否必交 | +| reportMinChars, reportMaxChars | 字数(对外称「字」) | +| reportMaxBytes, attachmentMaxBytes | 大小 | + +**发布实例** + +| 字段 | 说明 | +| --- | --- | +| problemId, classId / 指定学生 | 对象 | +| endTime | 正式截止 | +| allowMakeup | 是否允许补交 | +| makeupEndTime | 补交截止,允许补交时必填 | + +**评分标准维度(解析结果,≤10)** + +| 字段 | 说明 | +| --- | --- | +| name | 维度名 | +| maxScore | 该维满分 | +| bands | 分档说明(9–10 / 7–8 / …) | + +**提交** + +| 字段 | 说明 | +| --- | --- | +| reportPath, attachmentPath | 两个文件路径 | +| status | 未交/待批阅/AI/教师/打回 | +| submitTime, submitIp | 提交元数据 | +| extraDeadline | 该生加时截止 | +| reuploadGranted | 是否已获重传许可 | + +**AI 成绩(不覆盖)** + +| 字段 | 说明 | +| --- | --- | +| aiTotal | Σ aiDimNScore | +| aiOverallComment | 总体评语 | +| aiDim1Score, aiDim1Comment … aiDim10Score, aiDim10Comment | 空维留空 | + +**教师成绩(另存)** + +| 字段 | 说明 | +| --- | --- | +| teacherTotal | Σ teacherDimNScore | +| teacherOverallComment | 总体评语 | +| teacherDim1Score, teacherDim1Comment … | 与 AI 对称 | +| teacherId, reviewedAt | 审核人与时间 | + +**重传申请** + +| 字段 | 说明 | +| --- | --- | +| studentId, problemId, reason, status | 待审/同意/拒绝 | +| decidedBy, decidedAt | 教师处理 | + +**导出任务** + +| 字段 | 说明 | +| --- | --- | +| type | 报告 / 附件 / 成绩 / 未交名单 | +| filePath, expireAt, downloadedAt | 临时包与生命周期 | + +### 8.4 总分计算规则 + +```text +aiTotal = sum(aiDim i Score) i = 1..n, n ≤ 10 +teacherTotal = sum(teacherDim i Score) (教师保存时同样重算,不采用手工填的矛盾总分) +学生可见总分 = teacherTotal 存在 ? teacherTotal : aiTotal +``` + +### 8.5 文件存储 + +- 路径建议:`upload/{courseId}/{problemId}/{studentNo}/report.*` 与 `attachment.zip` +- 不把 docx 二进制写入 MySQL +- 批阅机只读报告文件的文字层 + +--- + +## 9. 非功能需求 + +**NFR-001 费用可控** + +每次成功进入批阅队列都应是教师可预期的。默认每生每题 1 次批阅;重传必须经教师同意。这是产品约束,不是优化项。 + +**NFR-002 长报告处理** + +字数上限的目的,是避免把完整 AI 对话和代码全部贴进报告导致切块后分数异常偏低。统计口径对外叫「字」,实现可用字符数;不要把「字符」这个词直接给师生看。 + +**NFR-003 导出体积** + +班级附件可能达数 GB。导出必须可分卷,临时包必须可过期删除。单份上限(500MB 或 1GB)做成配置。 + +**NFR-004 批阅时延** + +允许分钟到更长的排队,不要求提交接口秒级返回分数。需要让状态「待批阅」可被学生理解。 + +**NFR-005 安全** + +- 密钥、模型 API Key 不得写入仓库(现有 `original.py` 含明文 key,实现时应改为环境变量,旧 key 视为已泄露需轮换) +- 学生只能访问自己的提交;教师只能访问自己课程/班级 +- 上传文件按白名单解析,拒绝 zip 炸弹和可执行文件(P1,但 zip 内扩展名白名单是 P0) + +**NFR-006 可用性** + +校验失败必须返回中文原因。模型失败不得静默成 0 分。 + +**NFR-007 兼容现有 Demo 技术栈** + +默认继续:前端 Vue 3(AES-front,开发端口现为 3100),后端 Java Spring(AES,8082),MySQL(库名 `aes`),文件本地磁盘。批阅机可用 Python 独立进程,不必塞进 Tomcat 请求线程。 + +**NFR-008 规模假设** + +本阶段按单教师、若干班级、每课大约不超过 20 个大作业、每班约数百人设计。列表可以不分页。不按多租户 SaaS 设计。 + +--- + +## 10. 验收标准 + +下列条款全部满足,才视为本阶段需求落地。 + +### 10.1 学生端 + +- [ ] 入口为课程列表,作业列表含截止时间、补交信息、五种状态之一 +- [ ] 详情页:描述在上,附件在右,分数在附件下,已传文件可下载 +- [ ] 必交项、格式、大小、字数、可读性均在上传阶段拦截 +- [ ] 成功提交后不能直接再传;申请 → 教师同意 → 才能再传 +- [ ] 教师未审显示 AI 分;教师已审显示教师分 + +### 10.2 教师端 + +- [ ] 作业库新建:标题、描述、可生成并修改的评分标准、提交约束 +- [ ] 维度 > 10 或格式非法时不能保存,并提示正确格式 +- [ ] 发布可选班级/个人,可设补交截止,列表能看到补交信息与已交/待批/未交人数 +- [ ] 批阅页左右分栏,审核通过 / 修改 / 保存行为符合 FR-R-003,AI 字段仍在 +- [ ] 可打回、加时、导出成绩、分别导出报告与附件、导出未交名单 +- [ ] 不做批量打分、不显示题目正文于批阅页、没有作业统计页要求 + +### 10.3 批阅机 + +- [ ] 独立运行,提交后先「待批阅」 +- [ ] 只发送报告文字 + 评分标准 +- [ ] 总分等于分项之和 +- [ ] 分项写入固定字段,最多 10 维 + +### 10.4 导出 + +- [ ] 包内命名 `学号-姓名` +- [ ] 过大则分卷 +- [ ] 有过期时间提示;下载后或到期后删除 + +--- + +## 11. 分期计划 + +### 里程碑 A(P0 骨架,先能按新信息架构上课) + +1. 学生课程列表 + 作业列表五种状态 + 详情布局 +2. 双文件上传校验(格式/大小/必交;字数可先做简单版) +3. 作业库 / 已发布分离,发布含补交截止 +4. 提交后写待批阅,不再在 Web 请求里同步打分 + +### 里程碑 B(P0 批阅闭环) + +1. 评分标准生成 + 格式校验 + 最多 10 维入库 +2. 独立批阅机 + 分项字段 + 总分重算 +3. 教师批阅页(复制/审核通过/另存) +4. 申请重传 + 打回 + 加时 + +### 里程碑 C(P0 收尾) + +1. 导出报告 / 附件分卷 + 临时文件定时删除 +2. 导出成绩、未交名单 +3. 仓库清理与 `docs/` 数据库文档 +4. 字数统计与 zip 内文件可读性的完整校验 + +### 里程碑 D(P1 / P2) + +- 批阅失败自动重试与教师可见失败原因 +- 助教权限按班级细化 +- 管理员审批重传 +- 查重是否保留或与新状态机整合 +- 更多导出命名格式 +- 通知、统计图表、批量打分 + +建议实现顺序与导师关注点一致:**先改学生详情和列表状态,再改出题/评分标准,再做批阅机与导出**。导出是已交名单里最重的一块,不要堵在最小闭环之前。 + +--- + +## 12. 待确认问题 + +下列问题会议未最终钉死,实现前需向导师确认。未确认前采用「建议默认」。 + +| ID | 问题 | 谁来定 | 建议默认 | 是否阻塞编码 | +| --- | --- | --- | --- | --- | +| Q1 | 单份导出包上限取 500MB 还是 1GB | 导师 / 实现 | 配置项,默认 512MB | 否,先做配置 | +| Q2 | 报告默认大小 5MB、附件 10MB 是否写死为默认值 | 导师 | 作为新建作业默认值,教师可改 | 否 | +| Q3 | 「字数」按中文词还是 Unicode 字符 | 导师已倾向对外称字、对内字符 | 按字符数,界面写「字」 | 否 | +| Q4 | 审核通过时,若教师侧已有旧修改,是覆盖还是禁止 | 未讨论 | 已有教师稿时「审核通过」只改状态、不覆盖教师稿 | 否 | +| Q5 | 现有查重(`plagiarismStatus` 标红)本轮是否保留 | 未讨论 | 暂时保留字段,不在新列表里做主状态 | 否 | +| Q6 | 压缩包附件是否永远不送进大模型 | 会议按「只发报告文字」 | 不送 | 否 | +| Q7 | 重传申请是否要填写原因 | 未讨论 | 可选原因,教师列表能看到 | 否 | +| Q8 | 教师同意重传后,旧 AI 成绩是清空还是归档 | 未讨论 | 归档保留历史,当前成绩回到待批阅 | 建议先定 | +| Q9 | 批阅机与 Web 是否必须分两个可执行文件 | 会议说「也可以做成独立软件」 | 独立 Python/Java 进程 + 同一数据库 | 否 | +| Q10 | 学生课程列表 UI 是否必须像素级模仿导师截图 | 会议是「可以做成这个样子」 | 信息结构一致即可,不追视觉稿 | 否 | +| Q11 | 助教能否批阅、打回、同意重传 | 未重谈 | 沿用 Demo:助教可进作业管理,但重传审批先只开放教师 | 否 | +| Q12 | 评分标准编辑器用纯 Markdown 还是继续富文本 | 会议是富文本框 | 描述用富文本;标准用 Markdown 便于解析 | 建议先定 | + +--- + +## 13. 附录 + +### 13.1 会议中的关键原话(意译整理,便于追溯) + +- 一份作业就是一道题,不要「一、一」那种题号。 +- 学生详情:描述拉到最上面;右边改放附件;分数放在附件下面。 +- 学生不能随意上传,参照知网:传一次后要再传,向老师申请。 +- 作业列表至少要有截止时间、是否已传、分数;状态拆成未交、待批阅、分数(AI)、分数(教师)、打回。 +- 教师出题主要就两块:题目描述、发给大模型的评分标准。 +- 评分标准让模型按分档拆开;教师可改;保存必须符合格式。 +- 维度最多 10 个;用宽表存每维分数和评语。 +- 总分用各维度相加,不用模型给的 total。 +- 实验报告限制最少/最多字数和大小;附件一个 zip 也限制大小;是否必交打勾。 +- 格式由系统规定:docx / doc / pdf / zip,打不开就上传失败。 +- 发布要能选班级和个人,能设补交截止,列表上要能看到补交时间。 +- 批阅页不要再看题目;左 AI 右教师;改了另存,不覆盖 AI。 +- 不要批量打分;要批量打回、导出成绩、分别导出报告和附件。 +- 未交可以加时、批量加时、导出未交名单。 +- 导出按 `学号-姓名`,太大就拆包;下载完或保留一天后删。 +- 批阅做成独立软件,从数据库一条一条取,学生提交后要等一段时间。 +- Git 不要传无用二进制;数据库脚本放到 docs 当文档。 + +### 13.2 评分标准阶层结构(批阅机需要能解析) + +生成结果应能抽出类似结构(示例,字段名可在实现时固定): + +```text +总体:满分 100 +维度: + - 名称:团队协作 + 满分:10 + 分档: + 9-10:... + 7-8:... + 0-2:... + - 名称:... +注意事项:... (可对教师隐藏或保留,但解析规则要稳定) +``` + +批阅机输出应对齐为: + +```text +total = dim1.score + dim2.score + ... +overall_comment +dim1.score, dim1.comment +dim2.score, dim2.comment +... +``` + +这与导师现有本地批阅程序导出的 Excel(总分、总体评语、各维分数、各维评语)一致。 + +### 13.3 与现有代码的主要改造点(给开发用) + +| 位置 | 现状 | 需求方向 | +| --- | --- | --- | +| `AES-front/src/views/user/index.vue` | 宣传式首页 | 改为或跳转到课程列表 | +| `AES-front/src/views/user/exam-list/index.vue` | 全局作业表 + 分页 | 按课程过滤;状态列改为五种 | +| `AES-front/src/views/user/report-submit/*` | 左描述+上传,右评语 | 描述置顶,右附件,下分数;申请重传 | +| `AES-front/src/views/admin/problem/problem-edit.vue` | 维度表 + 权重 | 简要要求 + 生成 + 可编辑文稿 | +| `AES-front/src/views/admin/problem/problem-post.vue` | 有允许补交,无补交截止 | 补交截止;个人发布 | +| `AES-front/src/views/admin/problem/problem-review.vue` | 仍显示题目;教师一个总分 | 左右分项;审核通过/修改 | +| `AES-front/src/views/admin/problem/problem-student.vue` | 导出附件被注释 | 分报告/附件导出 | +| `AES/.../ProblemController.java` `/autoscore` | 请求内同步评分 | 改为入队;独立进程消费 | +| `AES/.../ProblemServiceImpl.java` `getAutoScore` | 按旧维度循环调 Python,评语拼接 | 一次(或按维)调用后写宽表;总分重算 | +| `submitreport` / `postproblem` / `scoringstandard` | 字段不足 | 按第 8 章扩展 | +| `original.py` | 含明文 API Key | 独立批阅机 + 环境变量 | + +### 13.4 文档技能与整理方法 + +为持续维护本需求,已在仓库安装: + +| Skill | 路径 | 用途 | +| --- | --- | --- | +| write-spec | `.cursor/skills/write-spec/SKILL.md` | 按 PRD 结构写目标、非目标、用户故事、P0/P1/P2 | +| prd-template | `.cursor/skills/prd-template/SKILL.md` | 编号需求、shall 句式、IEEE 29148 式章节 | +| meeting-to-spec | `.cursor/skills/meeting-to-spec/SKILL.md` | 从导师会议转写/速记抽取需求,区分 as-is 与 to-be | + +本次成稿时:以转写中导师决定为主,用速记补状态列表和数据字段,用 `aes.sql` 与前后端页面做差距表;会议明确「先不做」的能力一律写入非目标,未拍板的写入第 12 章。 + +### 13.5 原文索引 + +- 转写全文:`docs/通用语音识别_需求说明.mp4 (1).txt` +- 速记:`docs/自动评分系统/自动评分系统.md` +- 库结构现状:`aes.sql` diff --git a/original.py b/original.py index cbe187d..1b8f92e 100644 --- a/original.py +++ b/original.py @@ -1,6 +1,7 @@ import openai import time import re +import sys model = "Qwen/Qwen3-8B" max_tokens = 500 @@ -17,7 +18,7 @@ def getDim(content, dim): messages = [] messages.append({ "role": "system", - "content": "你是一位评分老师,请根据提供给你的评分标准对文本进行评分,结果仅仅输出分数,不需要任何解释" + "content": "你是一位评分老师,请根据提供给你的评分标准对文本进行评分,结果仅仅输出分数,满分为10分,分数允许小数点后保留两位,并就当前维度给出评语,评语文本不要过长。" "输出格式:" f"{output_format}" @@ -41,7 +42,10 @@ def getDim(content, dim): # else: # score = response.choices[0].message.content # print(score) - return response.choices[0].message.content + + # 去除多余的换行符 + content = response.choices[0].message.content.strip() + return content if __name__ == "__main__": content = sys.argv[1]