diff --git a/.gitignore b/.gitignore
index 9154f4c..326f057 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,5 @@
hs_err_pid*
replay_pid*
+.idea
+target
\ No newline at end of file
diff --git a/db/xm_examination.sql b/db/xm_examination.sql
new file mode 100644
index 0000000..afaff92
--- /dev/null
+++ b/db/xm_examination.sql
@@ -0,0 +1,271 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server : localhost_3306
+ Source Server Type : MySQL
+ Source Server Version : 80013
+ Source Host : localhost:3306
+ Source Schema : xm_examination
+
+ Target Server Type : MySQL
+ Target Server Version : 80013
+ File Encoding : 65001
+
+ Date: 12/10/2024 22:52:44
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for admin
+-- ----------------------------
+DROP TABLE IF EXISTS `admin`;
+CREATE TABLE `admin` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '账号',
+ `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '密码',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '姓名',
+ `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '头像',
+ `role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色',
+ `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '电话',
+ `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员表' ROW_FORMAT = DYNAMIC;
+
+-- ----------------------------
+-- Records of admin
+-- ----------------------------
+INSERT INTO `admin` VALUES (1, 'admin', 'admin', '管理员', 'http://localhost:9090/files/download/1721114905635-柴犬.jpeg', 'ADMIN', '18899990011', 'admin2@xm.com');
+
+-- ----------------------------
+-- Table structure for article
+-- ----------------------------
+DROP TABLE IF EXISTS `article`;
+CREATE TABLE `article` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '帖子标题',
+ `img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '帖子主图',
+ `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '帖子内容',
+ `time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发布时间',
+ `student_id` int(10) NULL DEFAULT NULL COMMENT '学生ID',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '帖子信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of article
+-- ----------------------------
+INSERT INTO `article` VALUES (2, '关于学习Java枚举的笔记经验分享', 'http://localhost:9090/files/download/1728563732106-2.png', '
基于Springboot3+Vue3的在线考试系统
角色:管理员、教师、学生
功能模块:
登录注册:(已完成)
个人中心:(已完成)
修改密码:(已完成)
管理员信息:(已完成)
教师信息:(已完成)
学生信息:(已完成)
考试安排:(已完成)
题型管理:包括单选、多选、判断、填空、简答(已完成)
课程管理:(已完成)
学习交流管理:
题库管理:题库里的题目需要根据课程进行分类,不同的课程都得有对应的题库,教师可以给自己的课程题库里新增试题(已完成)
组卷:选择课程出卷时,支持随机和人工从题库里抽选题目,组成试卷
试卷预览:
成绩管理:
自动阅卷:客观题自动阅卷,主观题(简答)可以支持手动给分
前台学生:
查看考试安排、查看试卷
在线答题:试卷每种题型在线展示,供学生答题
学习交流:发布学习心得
', '2024-10-10 20:35:34', 1);
+INSERT INTO `article` VALUES (3, '武哥10万字Springboot经典教程学习笔记', 'http://localhost:9090/files/download/1728564558044-9.png', '66666', '2024-10-10 20:49:20', 2);
+INSERT INTO `article` VALUES (5, '在线考试系统功能点描述分享', 'http://localhost:9090/files/download/1728564833337-10.png', '基于Springboot3+Vue3的在线考试系统
角色:管理员、教师、学生
功能模块:
登录注册:(已完成)
个人中心:(已完成)
修改密码:(已完成)
管理员信息:(已完成)
教师信息:(已完成)
学生信息:(已完成)
考试安排:(已完成)
题型管理:包括单选、多选、判断、填空、简答(已完成)
课程管理:(已完成)
学习交流管理:
题库管理:题库里的题目需要根据课程进行分类,不同的课程都得有对应的题库,教师可以给自己的课程题库里新增试题(已完成)
组卷:选择课程出卷时,支持随机和人工从题库里抽选题目,组成试卷
试卷预览:
成绩管理:
自动阅卷:客观题自动阅卷,主观题(简答)可以支持手动给分
前台学生:
查看考试安排、查看试卷
在线答题:试卷每种题型在线展示,供学生答题
学习交流:发布学习心得
', '2024-10-10 20:53:55', 1);
+INSERT INTO `article` VALUES (6, 'Vue3基础知识学习笔记', 'http://localhost:9090/files/download/1728568543079-7.png', '哈哈哈
呵呵呵
嘿嘿嘿
嘎嘎嘎
啦啦啦
', '2024-10-10 21:55:52', 1);
+INSERT INTO `article` VALUES (7, '前端三件套html,css,js学习心得', 'http://localhost:9090/files/download/1728568566399-right.jpg', '哈哈哈
哈哈哈
嘿嘿黑
呵呵呵
嘎嘎嘎
', '2024-10-10 21:56:13', 1);
+
+-- ----------------------------
+-- Table structure for course
+-- ----------------------------
+DROP TABLE IF EXISTS `course`;
+CREATE TABLE `course` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '课程名称',
+ `img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '课程封面',
+ `score` int(10) NULL DEFAULT NULL COMMENT '课程学分',
+ `teacher_id` int(10) NULL DEFAULT NULL COMMENT '教师ID',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '课程信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of course
+-- ----------------------------
+INSERT INTO `course` VALUES (2, 'Java基础入门课', 'http://localhost:9090/files/download/1728545691210-Java基础入门课程.jpg', 3, 1);
+INSERT INTO `course` VALUES (3, 'Vue最新实战教程', 'http://localhost:9090/files/download/1728545950698-Vue最新教程.jpg', 3, 1);
+INSERT INTO `course` VALUES (4, 'Java入学课程', 'http://localhost:9090/files/download/1728545989297-Java入学课程.jpg', 3, 2);
+
+-- ----------------------------
+-- Table structure for exam_plan
+-- ----------------------------
+DROP TABLE IF EXISTS `exam_plan`;
+CREATE TABLE `exam_plan` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '内容',
+ `time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发布时间',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '考试安排表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of exam_plan
+-- ----------------------------
+INSERT INTO `exam_plan` VALUES (1, '关于第一学期期末考试的安排', '考试时间:xxxx-xx-xx,考试地点:xxxx。注意事项:xxxx', '2024-10-10 14:21:13');
+INSERT INTO `exam_plan` VALUES (2, '关于考试考场纪律和作弊处罚措施', '本着公平公正原则,考试过程严禁作弊,请监考老师以及同学严格遵守,一旦发现,会取消该门课的考试资格,等待补考,如果补考作弊,该门课需要重修!', '2024-10-10 14:21:28');
+INSERT INTO `exam_plan` VALUES (3, '信息工程学院期末考试安排', '本着公平公正原则,考试过程严禁作弊,请监考老师以及同学严格遵守,一旦发现,会取消该门课的考试资格,等待补考,如果补考作弊,该门课需要重修!', '2024-10-10 14:21:40');
+INSERT INTO `exam_plan` VALUES (4, '软件学院期末考试安排', '考试时间:xxxx-xx-xx,考试地点:xxxx。注意事项:xxxx', '2024-10-10 14:21:51');
+INSERT INTO `exam_plan` VALUES (5, '经济管理学期末考试安排', '考试时间:xxxx-xx-xx,考试地点:xxxx。注意事项:xxxx', '2024-10-10 14:22:05');
+INSERT INTO `exam_plan` VALUES (6, '物流工程学院考试安排', '考试时间:xxxx-xx-xx,考试地点:xxxx。注意事项:xxxx', '2024-10-12 22:35:08');
+
+-- ----------------------------
+-- Table structure for notice
+-- ----------------------------
+DROP TABLE IF EXISTS `notice`;
+CREATE TABLE `notice` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '公告标题',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '公告内容',
+ `time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发布时间',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统公告表' ROW_FORMAT = DYNAMIC;
+
+-- ----------------------------
+-- Records of notice
+-- ----------------------------
+INSERT INTO `notice` VALUES (1, '今天天气真的不错', '今天好开心呀!因为天气很好,我又可以肆无忌惮的跟着武哥和青哥学习了!!真的好开心!', '2024-07-16 15:51:17');
+INSERT INTO `notice` VALUES (2, '项目所有功能开发完毕!', '我的项目所有的功能都开发完啦!真的很有成就感!', '2024-07-16 15:52:22');
+INSERT INTO `notice` VALUES (3, '项目功能都测试完成,准备上线!', '经过半个月的学习和练习,终于把这个项目完成了,可以打包上线了!', '2024-07-16 15:52:56');
+
+-- ----------------------------
+-- Table structure for question
+-- ----------------------------
+DROP TABLE IF EXISTS `question`;
+CREATE TABLE `question` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '题目名称',
+ `course_id` int(10) NULL DEFAULT NULL COMMENT '课程ID',
+ `teacher_id` int(10) NULL DEFAULT NULL COMMENT '教师ID',
+ `type_id` int(10) NULL DEFAULT NULL COMMENT '题型ID',
+ `option_a` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '选项A',
+ `option_b` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '选项B',
+ `option_c` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '选项C',
+ `option_d` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '选项D',
+ `answer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '题目答案',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '题目信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of question
+-- ----------------------------
+INSERT INTO `question` VALUES (2, 'Java是世界上最好的语言!', 2, 1, 3, NULL, NULL, NULL, NULL, '正确');
+INSERT INTO `question` VALUES (3, '下面哪一项不是Java基本数据类型?', 2, 1, 1, 'int', 'int', 'float', 'let', 'D');
+INSERT INTO `question` VALUES (4, '下面哪些选项是Java的特点?', 2, 1, 2, 'Java是后端语言', 'Java是前端语言', 'Java是强类型语言', 'Java是弱类型语言', 'A,C');
+INSERT INTO `question` VALUES (5, 'Java语言的创造者是______。', 2, 1, 4, NULL, NULL, NULL, NULL, 'James Gosling');
+INSERT INTO `question` VALUES (6, '请写一个冒泡排序算法。', 2, 1, 5, NULL, NULL, NULL, NULL, 'public void bubbleSort(int[] source) {\n for(int i = source.length - 1; i > 0; i--) {\n for(int j = 0; j < i; j++) {\n if(a[j] > a[j+1])\n swap(source, j, j+1); \n }\n }\n}');
+INSERT INTO `question` VALUES (7, '所有的Java项目里都有一个启动的______方法。', 4, 2, 4, NULL, NULL, NULL, NULL, 'main');
+
+-- ----------------------------
+-- Table structure for question_type
+-- ----------------------------
+DROP TABLE IF EXISTS `question_type`;
+CREATE TABLE `question_type` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '题型名称',
+ `score` int(10) NULL DEFAULT NULL COMMENT '题型分数',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '题型信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of question_type
+-- ----------------------------
+INSERT INTO `question_type` VALUES (1, '单选题', 4);
+INSERT INTO `question_type` VALUES (2, '多选题', 5);
+INSERT INTO `question_type` VALUES (3, '判断题', 2);
+INSERT INTO `question_type` VALUES (4, '填空题', 4);
+INSERT INTO `question_type` VALUES (5, '简答题', 20);
+
+-- ----------------------------
+-- Table structure for score
+-- ----------------------------
+DROP TABLE IF EXISTS `score`;
+CREATE TABLE `score` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '试卷名称',
+ `course_id` int(10) NULL DEFAULT NULL COMMENT '课程ID',
+ `teacher_id` int(10) NULL DEFAULT NULL COMMENT '教师ID',
+ `student_id` int(10) NULL DEFAULT NULL COMMENT '学生ID',
+ `paper_id` int(10) NULL DEFAULT NULL COMMENT '试卷ID',
+ `score` int(10) NULL DEFAULT NULL COMMENT '成绩得分',
+ `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '状态',
+ `answer` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '提交结果',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成绩信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of score
+-- ----------------------------
+INSERT INTO `score` VALUES (2, 'Java基础入门课小测验2', 2, 1, 1, 2, 13, '已阅卷', '[{\"typeName\":\"单选题\",\"questionId\":3,\"score\":4,\"answer\":\"D\",\"newAnswer\":\"D\"},{\"typeName\":\"多选题\",\"questionId\":4,\"score\":5,\"answer\":\"A,C\",\"newAnswer\":\"A,C\"},{\"typeName\":\"判断题\",\"questionId\":2,\"score\":2,\"answer\":\"正确\",\"newAnswer\":\"正确\"},{\"typeName\":\"填空题\",\"questionId\":5,\"score\":4,\"answer\":\"James Gosling\",\"newAnswer\":\"张三\"},{\"typeName\":\"简答题\",\"questionId\":6,\"score\":20,\"answer\":\"public void bubbleSort(int[] source) {\\n for(int i = source.length - 1; i > 0; i--) {\\n for(int j = 0; j < i; j++) {\\n if(a[j] > a[j+1])\\n swap(source, j, j+1); \\n }\\n }\\n}\",\"newAnswer\":\"public static void main() \"}]');
+INSERT INTO `score` VALUES (3, 'Java基础入门课小测验3', 2, 1, 1, 3, NULL, '待阅卷', '[{\"typeName\":\"单选题\",\"questionId\":3,\"score\":4,\"answer\":\"D\",\"newAnswer\":\"D\"},{\"typeName\":\"多选题\",\"questionId\":4,\"score\":5,\"answer\":\"A,C\",\"newAnswer\":\"A,C\"},{\"typeName\":\"简答题\",\"questionId\":6,\"score\":20,\"answer\":\"public void bubbleSort(int[] source) {\\n for(int i = source.length - 1; i > 0; i--) {\\n for(int j = 0; j < i; j++) {\\n if(a[j] > a[j+1])\\n swap(source, j, j+1); \\n }\\n }\\n}\",\"newAnswer\":\"public void bubbleSort(int[] source) {\\n for(int i = source.length - 1; i > 0; i--) {\\n for(int j = 0; j < i; j++) {\\n if(a[j] > a[j+1])\\n swap(source, j, j+1); \\n }\\n }\\n}\"}]');
+INSERT INTO `score` VALUES (4, 'Java基础入门课小测验1', 2, 1, 1, 1, 20, '已阅卷', '[{\"typeName\":\"判断题\",\"questionId\":2,\"score\":2,\"answer\":\"正确\",\"newAnswer\":\"正确\"},{\"typeName\":\"单选题\",\"questionId\":3,\"score\":4,\"answer\":\"D\",\"newAnswer\":\"D\"},{\"typeName\":\"多选题\",\"questionId\":4,\"score\":5,\"answer\":\"A,C\",\"newAnswer\":\"C,A\"},{\"typeName\":\"填空题\",\"questionId\":5,\"score\":4,\"answer\":\"James Gosling\",\"newAnswer\":\"James Gosling\"},{\"typeName\":\"简答题\",\"questionId\":6,\"score\":20,\"answer\":\"public void bubbleSort(int[] source) {\\n for(int i = source.length - 1; i > 0; i--) {\\n for(int j = 0; j < i; j++) {\\n if(a[j] > a[j+1])\\n swap(source, j, j+1); \\n }\\n }\\n}\",\"newAnswer\":\"public static void main( ) {\\n System.print......\\n 老师我不会了,给我点辛苦分吧~\\n}\"}]');
+
+-- ----------------------------
+-- Table structure for student
+-- ----------------------------
+DROP TABLE IF EXISTS `student`;
+CREATE TABLE `student` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '账号',
+ `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '密码',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '姓名',
+ `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '头像',
+ `role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色',
+ `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '电话',
+ `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
+ `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '状态',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of student
+-- ----------------------------
+INSERT INTO `student` VALUES (1, 'zhangsan', '123456', '张三', 'http://localhost:9090/files/download/1728486694570-柴犬.jpeg', 'STUDENT', '18899990000', 'zhangsan@xm.com', '审核通过');
+INSERT INTO `student` VALUES (2, 'lisi', '123456', '李四', 'http://localhost:9090/files/download/1728486728196-拉布拉多.jpeg', 'STUDENT', '18899995555', 'lisi@xm.com', '审核通过');
+INSERT INTO `student` VALUES (3, 'wangwu', '123456', '王五', 'http://localhost:9090/files/download/1728486753434-柯基.jpeg', 'STUDENT', '18844445555', 'wangwu@xm.com', '审核通过');
+INSERT INTO `student` VALUES (4, 'zhaoliu', '123456', 'zhaoliu', NULL, 'STUDENT', NULL, NULL, '待审核');
+
+-- ----------------------------
+-- Table structure for teacher
+-- ----------------------------
+DROP TABLE IF EXISTS `teacher`;
+CREATE TABLE `teacher` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '账号',
+ `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '密码',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '姓名',
+ `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '头像',
+ `role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色',
+ `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '电话',
+ `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '教师信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of teacher
+-- ----------------------------
+INSERT INTO `teacher` VALUES (1, 'zhang', '123456', '张老师', 'http://localhost:9090/files/download/1728484762449-柴犬.jpeg', 'TEACHER', '18800001111', 'zhang@xm.com');
+INSERT INTO `teacher` VALUES (2, 'li', '123456', '李老师', 'http://localhost:9090/files/download/1728484862680-柯基.jpeg', 'TEACHER', '18877776666', 'li@xm.com');
+INSERT INTO `teacher` VALUES (3, 'zhao', '123456', 'zhao', NULL, 'TEACHER', NULL, NULL);
+
+-- ----------------------------
+-- Table structure for test_paper
+-- ----------------------------
+DROP TABLE IF EXISTS `test_paper`;
+CREATE TABLE `test_paper` (
+ `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '试卷名称',
+ `course_id` int(10) NULL DEFAULT NULL COMMENT '课程ID',
+ `teacher_id` int(10) NULL DEFAULT NULL COMMENT '教师ID',
+ `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '类型',
+ `start` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '开始时间',
+ `end` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '结束时间',
+ `time` int(10) NULL DEFAULT NULL COMMENT '考试时长',
+ `question_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '题目IDs',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '试卷信息表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of test_paper
+-- ----------------------------
+INSERT INTO `test_paper` VALUES (1, 'Java基础入门课小测验1', 2, 1, '手动选题', '2024-10-11', '2024-10-26', 60, '[2,3,4,5,6]');
+INSERT INTO `test_paper` VALUES (2, 'Java基础入门课小测验2', 2, 1, '自动组卷', '2024-10-11', '2024-10-26', 60, '[3,4,2,5,6]');
+INSERT INTO `test_paper` VALUES (3, 'Java基础入门课小测验3', 2, 1, '自动组卷', '2024-10-11', '2024-10-24', 60, '[3,4,6]');
+INSERT INTO `test_paper` VALUES (4, 'Java基础入门小测验4', 2, 1, '手动选题', '2024-10-12', '2025-11-13', 60, '[3,4,2,6]');
+INSERT INTO `test_paper` VALUES (5, 'Java基础入门小测验5', 2, 1, '自动组卷', '2024-10-12', '2025-10-09', 60, '[3,4,2,5,6]');
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/files/1721114905635-柴犬.jpeg b/files/1721114905635-柴犬.jpeg
new file mode 100644
index 0000000..ec1ef01
Binary files /dev/null and b/files/1721114905635-柴犬.jpeg differ
diff --git a/files/1728484762449-柴犬.jpeg b/files/1728484762449-柴犬.jpeg
new file mode 100644
index 0000000..ec1ef01
Binary files /dev/null and b/files/1728484762449-柴犬.jpeg differ
diff --git a/files/1728484862680-柯基.jpeg b/files/1728484862680-柯基.jpeg
new file mode 100644
index 0000000..d78f64b
Binary files /dev/null and b/files/1728484862680-柯基.jpeg differ
diff --git a/files/1728486694570-柴犬.jpeg b/files/1728486694570-柴犬.jpeg
new file mode 100644
index 0000000..ec1ef01
Binary files /dev/null and b/files/1728486694570-柴犬.jpeg differ
diff --git a/files/1728486728196-拉布拉多.jpeg b/files/1728486728196-拉布拉多.jpeg
new file mode 100644
index 0000000..bbae442
Binary files /dev/null and b/files/1728486728196-拉布拉多.jpeg differ
diff --git a/files/1728486753434-柯基.jpeg b/files/1728486753434-柯基.jpeg
new file mode 100644
index 0000000..d78f64b
Binary files /dev/null and b/files/1728486753434-柯基.jpeg differ
diff --git a/files/1728545484737-Java基础入门课程.jpg b/files/1728545484737-Java基础入门课程.jpg
new file mode 100644
index 0000000..53aaf6a
Binary files /dev/null and b/files/1728545484737-Java基础入门课程.jpg differ
diff --git a/files/1728545691210-Java基础入门课程.jpg b/files/1728545691210-Java基础入门课程.jpg
new file mode 100644
index 0000000..53aaf6a
Binary files /dev/null and b/files/1728545691210-Java基础入门课程.jpg differ
diff --git a/files/1728545950698-Vue最新教程.jpg b/files/1728545950698-Vue最新教程.jpg
new file mode 100644
index 0000000..6cae207
Binary files /dev/null and b/files/1728545950698-Vue最新教程.jpg differ
diff --git a/files/1728545989297-Java入学课程.jpg b/files/1728545989297-Java入学课程.jpg
new file mode 100644
index 0000000..48c0a73
Binary files /dev/null and b/files/1728545989297-Java入学课程.jpg differ
diff --git a/files/1728563597926-2.png b/files/1728563597926-2.png
new file mode 100644
index 0000000..bfccb63
Binary files /dev/null and b/files/1728563597926-2.png differ
diff --git a/files/1728563732106-2.png b/files/1728563732106-2.png
new file mode 100644
index 0000000..bfccb63
Binary files /dev/null and b/files/1728563732106-2.png differ
diff --git a/files/1728564558044-9.png b/files/1728564558044-9.png
new file mode 100644
index 0000000..1a8446d
Binary files /dev/null and b/files/1728564558044-9.png differ
diff --git a/files/1728564626540-10.png b/files/1728564626540-10.png
new file mode 100644
index 0000000..27ce7e2
Binary files /dev/null and b/files/1728564626540-10.png differ
diff --git a/files/1728564833337-10.png b/files/1728564833337-10.png
new file mode 100644
index 0000000..27ce7e2
Binary files /dev/null and b/files/1728564833337-10.png differ
diff --git a/files/1728566947212-柴犬.jpeg b/files/1728566947212-柴犬.jpeg
new file mode 100644
index 0000000..ec1ef01
Binary files /dev/null and b/files/1728566947212-柴犬.jpeg differ
diff --git a/files/1728568543079-7.png b/files/1728568543079-7.png
new file mode 100644
index 0000000..8df622b
Binary files /dev/null and b/files/1728568543079-7.png differ
diff --git a/files/1728568566399-right.jpg b/files/1728568566399-right.jpg
new file mode 100644
index 0000000..3150b0b
Binary files /dev/null and b/files/1728568566399-right.jpg differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..104293a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,78 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.1
+
+
+ com.example
+ java-experiment
+ 0.0.1-SNAPSHOT
+ springboot
+ springboot
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 3.0.3
+
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+
+ cn.hutool
+ hutool-all
+ 5.8.25
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+ 1.4.6
+
+
+ org.mybatis
+ mybatis
+
+
+
+
+
+
+ com.auth0
+ java-jwt
+ 4.3.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/src/main/java/com/example/SpringbootApplication.java b/src/main/java/com/example/SpringbootApplication.java
new file mode 100644
index 0000000..f0d2eb2
--- /dev/null
+++ b/src/main/java/com/example/SpringbootApplication.java
@@ -0,0 +1,13 @@
+package com.example;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.example.mapper")
+public class SpringbootApplication { public static void main(String[] args) {
+ SpringApplication.run(SpringbootApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/example/common/Constants.java b/src/main/java/com/example/common/Constants.java
new file mode 100644
index 0000000..2e09293
--- /dev/null
+++ b/src/main/java/com/example/common/Constants.java
@@ -0,0 +1,7 @@
+package com.example.common;
+
+public interface Constants {
+
+ String TOKEN = "token";
+ String USER_DEFAULT_PASSWORD = "123456";
+}
diff --git a/src/main/java/com/example/common/Result.java b/src/main/java/com/example/common/Result.java
new file mode 100644
index 0000000..22ac335
--- /dev/null
+++ b/src/main/java/com/example/common/Result.java
@@ -0,0 +1,70 @@
+package com.example.common;
+
+public class Result {
+
+ private String code;
+ private String msg;
+ private Object data;
+
+ public Result() {
+
+ }
+
+ public static Result success() {
+ Result result = new Result();
+ result.setCode("200");
+ result.setMsg("请求成功");
+ return result;
+ }
+
+ public static Result success(Object data) {
+ Result result = success();
+ result.setData(data);
+ return result;
+ }
+
+ public static Result error() {
+ Result result = new Result();
+ result.setCode("500");
+ result.setMsg("系统异常");
+ return result;
+ }
+
+ public static Result error(String code, String msg) {
+ Result result = new Result();
+ result.setCode(code);
+ result.setMsg(msg);
+ return result;
+ }
+
+ public static Result error(String msg) {
+ Result result = new Result();
+ result.setCode("500");
+ result.setMsg(msg);
+ return result;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+}
diff --git a/src/main/java/com/example/common/config/CorsConfig.java b/src/main/java/com/example/common/config/CorsConfig.java
new file mode 100644
index 0000000..9be21e6
--- /dev/null
+++ b/src/main/java/com/example/common/config/CorsConfig.java
@@ -0,0 +1,25 @@
+package com.example.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+/**
+ * 跨域配置
+ */
+@Configuration
+public class CorsConfig {
+
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
+ corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
+ corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
+ source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
+ return new CorsFilter(source);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/common/config/JWTInterceptor.java b/src/main/java/com/example/common/config/JWTInterceptor.java
new file mode 100644
index 0000000..6eadc9b
--- /dev/null
+++ b/src/main/java/com/example/common/config/JWTInterceptor.java
@@ -0,0 +1,81 @@
+package com.example.common.config;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.example.common.Constants;
+import com.example.common.enums.ResultCodeEnum;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.exception.CustomException;
+import com.example.service.AdminService;
+import com.example.service.StudentService;
+import com.example.service.TeacherService;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+/**
+ * JWT拦截器
+ */
+@Component
+public class JWTInterceptor implements HandlerInterceptor {
+
+ @Resource
+ private AdminService adminService;
+ @Resource
+ private TeacherService teacherService;
+ @Resource
+ private StudentService studentService;
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ // 1. 从http请求标头里面拿到token
+ String token = request.getHeader(Constants.TOKEN);
+ if (ObjectUtil.isNull(token)) {
+ // 如果没拿到,那么再从请求参数里拿一次
+ request.getParameter(Constants.TOKEN);
+ }
+ // 2. 开始执行认证
+ if (ObjectUtil.isNull(token)) {
+ throw new CustomException(ResultCodeEnum.TOKEN_INVALID_ERROR);
+ }
+ Account account = null;
+ try {
+ String audience = JWT.decode(token).getAudience().get(0);
+ String userId = audience.split("-")[0];
+ String role = audience.split("-")[1];
+ // 根据用户角色判断用户属于哪个数据库表 然后查询用户数据
+ if (RoleEnum.ADMIN.name().equals(role)) {
+ account = adminService.selectById(Integer.valueOf(userId));
+ }
+ if (RoleEnum.TEACHER.name().equals(role)) {
+ account = teacherService.selectById(Integer.valueOf(userId));
+ }
+ if (RoleEnum.STUDENT.name().equals(role)) {
+ account = studentService.selectById(Integer.valueOf(userId));
+ }
+ } catch (Exception e) {
+ throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
+ }
+ // 根据token里面携带的用户ID去对应的角色表查询 没查到 所有报了这个“用户不存在”错误
+ if (ObjectUtil.isNull(account)) {
+ // 用户不存在
+ throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
+ }
+ try {
+ // 通过用户的密码作为密钥再次验证token的合法性
+ JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(account.getPassword())).build();
+ jwtVerifier.verify(token); // 验证token
+ } catch (JWTVerificationException e) {
+ // 用户不存在
+ throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/example/common/config/WebConfig.java b/src/main/java/com/example/common/config/WebConfig.java
new file mode 100644
index 0000000..5d7d975
--- /dev/null
+++ b/src/main/java/com/example/common/config/WebConfig.java
@@ -0,0 +1,21 @@
+package com.example.common.config;
+
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+ @Resource
+ private JWTInterceptor jwtInterceptor;
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(jwtInterceptor).addPathPatterns("/**")
+ .excludePathPatterns("/")
+ .excludePathPatterns("/login", "/register", "/files/**");
+ }
+
+}
diff --git a/src/main/java/com/example/common/enums/ResultCodeEnum.java b/src/main/java/com/example/common/enums/ResultCodeEnum.java
new file mode 100644
index 0000000..7b6e41e
--- /dev/null
+++ b/src/main/java/com/example/common/enums/ResultCodeEnum.java
@@ -0,0 +1,26 @@
+package com.example.common.enums;
+
+public enum ResultCodeEnum {
+
+ SUCCESS("200", "成功"),
+ PARAM_ERROR("400", "参数异常"),
+ TOKEN_INVALID_ERROR("401", "无效的token"),
+ TOKEN_CHECK_ERROR("401", "token验证失败,请重新登录"),
+ PARAM_LOST_ERROR("4001", "参数缺失"),
+
+ SYSTEM_ERROR("500", "系统异常"),
+ USER_EXIST_ERROR("5001", "用户名已存在"),
+ USER_NOT_LOGIN("5002", "用户未登录"),
+ USER_ACCOUNT_ERROR("5003", "账号或密码错误"),
+ USER_NOT_EXIST_ERROR("5004", "用户不存在"),
+ PARAM_PASSWORD_ERROR("5005", "原密码输入错误"),
+ ;
+
+ public String code;
+ public String msg;
+
+ ResultCodeEnum(String code, String msg) {
+ this.code = code;
+ this.msg = msg;
+ }
+}
diff --git a/src/main/java/com/example/common/enums/RoleEnum.java b/src/main/java/com/example/common/enums/RoleEnum.java
new file mode 100644
index 0000000..cf7aed7
--- /dev/null
+++ b/src/main/java/com/example/common/enums/RoleEnum.java
@@ -0,0 +1,10 @@
+package com.example.common.enums;
+
+public enum RoleEnum {
+ // 管理员
+ ADMIN,
+ // 教师
+ TEACHER,
+ // 学生
+ STUDENT
+}
diff --git a/src/main/java/com/example/controller/AdminController.java b/src/main/java/com/example/controller/AdminController.java
new file mode 100644
index 0000000..7783195
--- /dev/null
+++ b/src/main/java/com/example/controller/AdminController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Admin;
+import com.example.service.AdminService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 前端请求接口
+ */
+@RestController
+@RequestMapping("/admin")
+public class AdminController {
+
+ @Resource
+ private AdminService adminService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Admin admin) {
+ adminService.add(admin);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Admin admin) {
+ adminService.updateById(admin);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ adminService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ adminService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Admin admin = adminService.selectById(id);
+ return Result.success(admin);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Admin admin) {
+ List list = adminService.selectAll(admin);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Admin admin,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = adminService.selectPage(admin, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/ArticleController.java b/src/main/java/com/example/controller/ArticleController.java
new file mode 100644
index 0000000..7c0ffa8
--- /dev/null
+++ b/src/main/java/com/example/controller/ArticleController.java
@@ -0,0 +1,93 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Article;
+import com.example.service.ArticleService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 帖子信息前端请求接口
+ */
+@RestController
+@RequestMapping("/article")
+public class ArticleController {
+
+ @Resource
+ private ArticleService articleService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Article article) {
+ articleService.add(article);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Article article) {
+ articleService.updateById(article);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ articleService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ articleService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Article article = articleService.selectById(id);
+ return Result.success(article);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Article article) {
+ List list = articleService.selectAll(article);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Article article,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = articleService.selectPage(article, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+ @GetMapping("/selectRandom")
+ public Result selectRandom() {
+ List list = articleService.selectRandom();
+ return Result.success(list);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/CourseController.java b/src/main/java/com/example/controller/CourseController.java
new file mode 100644
index 0000000..658ce38
--- /dev/null
+++ b/src/main/java/com/example/controller/CourseController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Course;
+import com.example.service.CourseService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 课程信息前端请求接口
+ */
+@RestController
+@RequestMapping("/course")
+public class CourseController {
+
+ @Resource
+ private CourseService courseService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Course course) {
+ courseService.add(course);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Course course) {
+ courseService.updateById(course);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ courseService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ courseService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Course course = courseService.selectById(id);
+ return Result.success(course);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Course course) {
+ List list = courseService.selectAll(course);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Course course,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = courseService.selectPage(course, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/ExamPlanController.java b/src/main/java/com/example/controller/ExamPlanController.java
new file mode 100644
index 0000000..54e37f5
--- /dev/null
+++ b/src/main/java/com/example/controller/ExamPlanController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.ExamPlan;
+import com.example.service.ExamPlanService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 考试安排前端请求接口
+ */
+@RestController
+@RequestMapping("/examPlan")
+public class ExamPlanController {
+
+ @Resource
+ private ExamPlanService examPlanService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody ExamPlan examPlan) {
+ examPlanService.add(examPlan);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody ExamPlan examPlan) {
+ examPlanService.updateById(examPlan);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ examPlanService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ examPlanService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ ExamPlan examPlan = examPlanService.selectById(id);
+ return Result.success(examPlan);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(ExamPlan examPlan) {
+ List list = examPlanService.selectAll(examPlan);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(ExamPlan examPlan,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = examPlanService.selectPage(examPlan, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/FileController.java b/src/main/java/com/example/controller/FileController.java
new file mode 100644
index 0000000..ad4c9cc
--- /dev/null
+++ b/src/main/java/com/example/controller/FileController.java
@@ -0,0 +1,96 @@
+package com.example.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.StrUtil;
+import com.example.common.Result;
+import jakarta.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/files")
+public class FileController {
+
+ private static final Logger log = LoggerFactory.getLogger(FileController.class);
+
+ private static final String filePath = System.getProperty("user.dir") + "/files/";
+
+ @Value("${fileBaseUrl:}")
+ private String fileBaseUrl;
+
+ /**
+ * 文件上传
+ */
+ @PostMapping("/upload")
+ public Result upload(MultipartFile file) {
+ String fileName = file.getOriginalFilename();
+ try {
+ if (!FileUtil.isDirectory(filePath)) {
+ FileUtil.mkdir(filePath);
+ }
+ fileName = System.currentTimeMillis() + "-" + fileName;
+ String realFilePath = filePath + fileName;
+ // 文件存储形式:时间戳-文件名
+ FileUtil.writeBytes(file.getBytes(), realFilePath);
+ } catch (Exception e) {
+ log.error(fileName + "--文件上传失败", e);
+ }
+ String url = fileBaseUrl + "/files/download/" + fileName;
+ return Result.success(url);
+ }
+
+ /**
+ * 获取文件
+ */
+ @GetMapping("/download/{fileName}")
+ public void download(@PathVariable String fileName, HttpServletResponse response) {
+ OutputStream os;
+ try {
+ if (StrUtil.isNotEmpty(fileName)) {
+ response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
+ response.setContentType("application/octet-stream");
+ byte[] bytes = FileUtil.readBytes(filePath + fileName);
+ os = response.getOutputStream();
+ os.write(bytes);
+ os.flush();
+ os.close();
+ }
+ } catch (Exception e) {
+ log.warn("文件下载失败:" + fileName);
+ }
+ }
+
+ /**
+ * wang-editor编辑器文件上传接口
+ */
+ @PostMapping("/wang/upload")
+ public Map wangEditorUpload(MultipartFile file) {
+ String flag = System.currentTimeMillis() + "";
+ String fileName = file.getOriginalFilename();
+ try {
+ // 文件存储形式:时间戳-文件名
+ FileUtil.writeBytes(file.getBytes(), filePath + flag + "-" + fileName);
+ System.out.println(fileName + "--上传成功");
+ Thread.sleep(1L);
+ } catch (Exception e) {
+ System.err.println(fileName + "--文件上传失败");
+ }
+ String http = fileBaseUrl + "/files/download/";
+ Map resMap = new HashMap<>();
+ // wangEditor上传图片成功后, 需要返回的参数
+ resMap.put("errno", 0);
+ resMap.put("data", CollUtil.newArrayList(Dict.create().set("url", http + flag + "-" + fileName)));
+ return resMap;
+ }
+}
diff --git a/src/main/java/com/example/controller/NoticeController.java b/src/main/java/com/example/controller/NoticeController.java
new file mode 100644
index 0000000..891d9de
--- /dev/null
+++ b/src/main/java/com/example/controller/NoticeController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Notice;
+import com.example.service.NoticeService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 前端请求接口
+ */
+@RestController
+@RequestMapping("/notice")
+public class NoticeController {
+
+ @Resource
+ private NoticeService noticeService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Notice notice) {
+ noticeService.add(notice);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Notice notice) {
+ noticeService.updateById(notice);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ noticeService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ noticeService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Notice notice = noticeService.selectById(id);
+ return Result.success(notice);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Notice notice) {
+ List list = noticeService.selectAll(notice);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Notice notice,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = noticeService.selectPage(notice, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/QuestionController.java b/src/main/java/com/example/controller/QuestionController.java
new file mode 100644
index 0000000..f363224
--- /dev/null
+++ b/src/main/java/com/example/controller/QuestionController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Question;
+import com.example.service.QuestionService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 题目信息前端请求接口
+ */
+@RestController
+@RequestMapping("/question")
+public class QuestionController {
+
+ @Resource
+ private QuestionService questionService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Question question) {
+ questionService.add(question);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Question question) {
+ questionService.updateById(question);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ questionService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ questionService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Question question = questionService.selectById(id);
+ return Result.success(question);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Question question) {
+ List list = questionService.selectAll(question);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Question question,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = questionService.selectPage(question, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/QuestionTypeController.java b/src/main/java/com/example/controller/QuestionTypeController.java
new file mode 100644
index 0000000..d4a8cc6
--- /dev/null
+++ b/src/main/java/com/example/controller/QuestionTypeController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.QuestionType;
+import com.example.service.QuestionTypeService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 题型信息前端请求接口
+ */
+@RestController
+@RequestMapping("/questionType")
+public class QuestionTypeController {
+
+ @Resource
+ private QuestionTypeService questionTypeService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody QuestionType questionType) {
+ questionTypeService.add(questionType);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody QuestionType questionType) {
+ questionTypeService.updateById(questionType);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ questionTypeService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ questionTypeService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ QuestionType questionType = questionTypeService.selectById(id);
+ return Result.success(questionType);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(QuestionType questionType) {
+ List list = questionTypeService.selectAll(questionType);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(QuestionType questionType,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = questionTypeService.selectPage(questionType, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/ScoreController.java b/src/main/java/com/example/controller/ScoreController.java
new file mode 100644
index 0000000..e2331d1
--- /dev/null
+++ b/src/main/java/com/example/controller/ScoreController.java
@@ -0,0 +1,94 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Answer;
+import com.example.entity.Score;
+import com.example.entity.TestPaper;
+import com.example.service.ScoreService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 试卷信息前端请求接口
+ */
+@RestController
+@RequestMapping("/score")
+public class ScoreController {
+
+ @Resource
+ private ScoreService scoreService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody TestPaper testPaper) {
+ scoreService.add(testPaper);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Score score) {
+ scoreService.updateById(score);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ scoreService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ scoreService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Score score = scoreService.selectById(id);
+ return Result.success(score);
+ }
+ @GetMapping("/selectAnswer/{id}")
+ public Result selectAnswer(@PathVariable Integer id) {
+ List list = scoreService.selectAnswer(id);
+ return Result.success(list);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Score score) {
+ List list = scoreService.selectAll(score);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Score score,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = scoreService.selectPage(score, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/StudentController.java b/src/main/java/com/example/controller/StudentController.java
new file mode 100644
index 0000000..5e36dd1
--- /dev/null
+++ b/src/main/java/com/example/controller/StudentController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Student;
+import com.example.service.StudentService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 学生信息前端请求接口
+ */
+@RestController
+@RequestMapping("/student")
+public class StudentController {
+
+ @Resource
+ private StudentService studentService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Student student) {
+ studentService.add(student);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Student student) {
+ studentService.updateById(student);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ studentService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ studentService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Student student = studentService.selectById(id);
+ return Result.success(student);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Student student) {
+ List list = studentService.selectAll(student);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Student student,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = studentService.selectPage(student, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/TeacherController.java b/src/main/java/com/example/controller/TeacherController.java
new file mode 100644
index 0000000..cd9da22
--- /dev/null
+++ b/src/main/java/com/example/controller/TeacherController.java
@@ -0,0 +1,87 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.Teacher;
+import com.example.service.TeacherService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 教师信息前端请求接口
+ */
+@RestController
+@RequestMapping("/teacher")
+public class TeacherController {
+
+ @Resource
+ private TeacherService teacherService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Teacher teacher) {
+ teacherService.add(teacher);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody Teacher teacher) {
+ teacherService.updateById(teacher);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ teacherService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ teacherService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ Teacher teacher = teacherService.selectById(id);
+ return Result.success(teacher);
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(Teacher teacher) {
+ List list = teacherService.selectAll(teacher);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(Teacher teacher,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) {
+ PageInfo pageInfo = teacherService.selectPage(teacher, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/TestPaperController.java b/src/main/java/com/example/controller/TestPaperController.java
new file mode 100644
index 0000000..2a83b97
--- /dev/null
+++ b/src/main/java/com/example/controller/TestPaperController.java
@@ -0,0 +1,100 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.entity.TestPaper;
+import com.example.service.TestPaperService;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.ParseException;
+import java.util.List;
+
+/**
+ * 试卷信息前端请求接口
+ */
+@RestController
+@RequestMapping("/testPaper")
+public class TestPaperController {
+
+ @Resource
+ private TestPaperService testPaperService;
+
+ /**
+ * 新增
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody TestPaper testPaper) throws ParseException {
+ testPaperService.add(testPaper);
+ return Result.success();
+ }
+
+ /**
+ * 修改
+ */
+ @PutMapping("/update")
+ public Result update(@RequestBody TestPaper testPaper) {
+ testPaperService.updateById(testPaper);
+ return Result.success();
+ }
+
+ /**
+ * 单个删除
+ */
+ @DeleteMapping("/delete/{id}")
+ public Result delete(@PathVariable Integer id) {
+ testPaperService.deleteById(id);
+ return Result.success();
+ }
+
+ /**
+ * 批量删除
+ */
+ @DeleteMapping("/delete/batch")
+ public Result delete(@RequestBody List ids) {
+ testPaperService.deleteBatch(ids);
+ return Result.success();
+ }
+
+ /**
+ * 单个查询
+ */
+ @GetMapping("/selectById/{id}")
+ public Result selectById(@PathVariable Integer id) {
+ TestPaper testPaper = testPaperService.selectById(id);
+ return Result.success(testPaper);
+ }
+
+ @GetMapping("/check/{id}")
+ public Result check(@PathVariable Integer id) {
+ testPaperService.checkTestPaper(id);
+ return Result.success();
+ }
+
+ /**
+ * 查询所有
+ */
+ @GetMapping("/selectAll")
+ public Result selectAll(TestPaper testPaper) {
+ List list = testPaperService.selectAll(testPaper);
+ return Result.success(list);
+ }
+
+ /**
+ * 分页查询
+ */
+ @GetMapping("/selectPage")
+ public Result selectPage(TestPaper testPaper,
+ @RequestParam(defaultValue = "1") Integer pageNum,
+ @RequestParam(defaultValue = "10") Integer pageSize) throws ParseException {
+ PageInfo pageInfo = testPaperService.selectPage(testPaper, pageNum, pageSize);
+ return Result.success(pageInfo);
+ }
+
+ @GetMapping("/selectRandom")
+ public Result selectRandom() throws ParseException {
+ List list = testPaperService.selectRandom();
+ return Result.success(list);
+ }
+
+}
diff --git a/src/main/java/com/example/controller/WebController.java b/src/main/java/com/example/controller/WebController.java
new file mode 100644
index 0000000..e81888d
--- /dev/null
+++ b/src/main/java/com/example/controller/WebController.java
@@ -0,0 +1,79 @@
+package com.example.controller;
+
+import com.example.common.Result;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.service.AdminService;
+import com.example.service.StudentService;
+import com.example.service.TeacherService;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+public class WebController {
+
+ @Resource
+ private AdminService adminService;
+ @Resource
+ private TeacherService teacherService;
+ @Resource
+ private StudentService studentService;
+
+ /**
+ * 默认请求接口
+ */
+ @GetMapping("/")
+ public Result hello () {
+ return Result.success();
+ }
+
+ /**
+ * 登录
+ */
+ @PostMapping("/login")
+ public Result login(@RequestBody Account account) {
+ Account loginAccount = null;
+ if (RoleEnum.ADMIN.name().equals(account.getRole())) {
+ loginAccount = adminService.login(account);
+ }
+ if (RoleEnum.TEACHER.name().equals(account.getRole())) {
+ loginAccount = teacherService.login(account);
+ }
+ if (RoleEnum.STUDENT.name().equals(account.getRole())) {
+ loginAccount = studentService.login(account);
+ }
+ return Result.success(loginAccount);
+ }
+
+ /**
+ * 注册
+ */
+ @PostMapping("/register")
+ public Result register(@RequestBody Account account) {
+ if (RoleEnum.TEACHER.name().equals(account.getRole())) {
+ teacherService.register(account);
+ }
+ if (RoleEnum.STUDENT.name().equals(account.getRole())) {
+ studentService.register(account);
+ }
+ return Result.success();
+ }
+
+ /**
+ * 修改密码
+ */
+ @PutMapping("/updatePassword")
+ public Result updatePassword(@RequestBody Account account) {
+ if (RoleEnum.ADMIN.name().equals(account.getRole())) {
+ adminService.updatePassword(account);
+ }
+ if (RoleEnum.TEACHER.name().equals(account.getRole())) {
+ teacherService.updatePassword(account);
+ }
+ if (RoleEnum.STUDENT.name().equals(account.getRole())) {
+ studentService.updatePassword(account);
+ }
+ return Result.success();
+ }
+
+}
diff --git a/src/main/java/com/example/entity/Account.java b/src/main/java/com/example/entity/Account.java
new file mode 100644
index 0000000..78c96e7
--- /dev/null
+++ b/src/main/java/com/example/entity/Account.java
@@ -0,0 +1,59 @@
+package com.example.entity;
+
+public class Account {
+
+ private Integer id;
+ private String username;
+ private String password;
+ private String role;
+ private String newPassword;
+ private String token;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getNewPassword() {
+ return newPassword;
+ }
+
+ public void setNewPassword(String newPassword) {
+ this.newPassword = newPassword;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+}
diff --git a/src/main/java/com/example/entity/Admin.java b/src/main/java/com/example/entity/Admin.java
new file mode 100644
index 0000000..b40aa42
--- /dev/null
+++ b/src/main/java/com/example/entity/Admin.java
@@ -0,0 +1,79 @@
+package com.example.entity;
+
+public class Admin extends Account {
+
+ /** 主键ID */
+ private Integer id;
+ /** 账号 */
+ private String username;
+ private String password;
+ private String name;
+ private String avatar;
+ private String role;
+ private String phone;
+ private String email;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+}
diff --git a/src/main/java/com/example/entity/Answer.java b/src/main/java/com/example/entity/Answer.java
new file mode 100644
index 0000000..3167b67
--- /dev/null
+++ b/src/main/java/com/example/entity/Answer.java
@@ -0,0 +1,70 @@
+package com.example.entity;
+
+public class Answer {
+
+ private String typeName;
+ private Integer questionId;
+ private Integer score;
+ private String answer;
+ private String newAnswer;
+ private Integer result;
+
+ private String questionName;
+
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public void setTypeName(String typeName) {
+ this.typeName = typeName;
+ }
+
+ public Integer getQuestionId() {
+ return questionId;
+ }
+
+ public void setQuestionId(Integer questionId) {
+ this.questionId = questionId;
+ }
+
+ public Integer getScore() {
+ return score;
+ }
+
+ public void setScore(Integer score) {
+ this.score = score;
+ }
+
+ public String getAnswer() {
+ return answer;
+ }
+
+ public void setAnswer(String answer) {
+ this.answer = answer;
+ }
+
+ public String getNewAnswer() {
+ return newAnswer;
+ }
+
+ public void setNewAnswer(String newAnswer) {
+ this.newAnswer = newAnswer;
+ }
+
+ public Integer getResult() {
+ return result;
+ }
+
+ public void setResult(Integer result) {
+ this.result = result;
+ }
+
+ public String getQuestionName() {
+ return questionName;
+ }
+
+ public void setQuestionName(String questionName) {
+ this.questionName = questionName;
+ }
+}
diff --git a/src/main/java/com/example/entity/Article.java b/src/main/java/com/example/entity/Article.java
new file mode 100644
index 0000000..8deb591
--- /dev/null
+++ b/src/main/java/com/example/entity/Article.java
@@ -0,0 +1,77 @@
+package com.example.entity;
+
+public class Article {
+ private Integer id;
+ private String title;
+ private String img;
+ private String content;
+ private String time;
+ private Integer studentId;
+
+ private String studentName;
+ private String studentAvatar;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getImg() {
+ return img;
+ }
+
+ public void setImg(String img) {
+ this.img = img;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public void setTime(String time) {
+ this.time = time;
+ }
+
+ public Integer getStudentId() {
+ return studentId;
+ }
+
+ public void setStudentId(Integer studentId) {
+ this.studentId = studentId;
+ }
+
+ public String getStudentName() {
+ return studentName;
+ }
+
+ public void setStudentName(String studentName) {
+ this.studentName = studentName;
+ }
+
+ public String getStudentAvatar() {
+ return studentAvatar;
+ }
+
+ public void setStudentAvatar(String studentAvatar) {
+ this.studentAvatar = studentAvatar;
+ }
+}
diff --git a/src/main/java/com/example/entity/Course.java b/src/main/java/com/example/entity/Course.java
new file mode 100644
index 0000000..ab81cbe
--- /dev/null
+++ b/src/main/java/com/example/entity/Course.java
@@ -0,0 +1,58 @@
+package com.example.entity;
+
+public class Course {
+ private Integer id;
+ private String name;
+ private String img;
+ private Integer score;
+ private Integer teacherId;
+ private String teacherName;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getImg() {
+ return img;
+ }
+
+ public void setImg(String img) {
+ this.img = img;
+ }
+
+ public Integer getScore() {
+ return score;
+ }
+
+ public void setScore(Integer score) {
+ this.score = score;
+ }
+
+ public Integer getTeacherId() {
+ return teacherId;
+ }
+
+ public void setTeacherId(Integer teacherId) {
+ this.teacherId = teacherId;
+ }
+
+ public String getTeacherName() {
+ return teacherName;
+ }
+
+ public void setTeacherName(String teacherName) {
+ this.teacherName = teacherName;
+ }
+}
diff --git a/src/main/java/com/example/entity/ExamPlan.java b/src/main/java/com/example/entity/ExamPlan.java
new file mode 100644
index 0000000..47fef7d
--- /dev/null
+++ b/src/main/java/com/example/entity/ExamPlan.java
@@ -0,0 +1,40 @@
+package com.example.entity;
+
+public class ExamPlan {
+ private Integer id;
+ private String title;
+ private String content;
+ private String time;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public void setTime(String time) {
+ this.time = time;
+ }
+}
diff --git a/src/main/java/com/example/entity/Notice.java b/src/main/java/com/example/entity/Notice.java
new file mode 100644
index 0000000..31cb6f6
--- /dev/null
+++ b/src/main/java/com/example/entity/Notice.java
@@ -0,0 +1,40 @@
+package com.example.entity;
+
+public class Notice {
+ private Integer id;
+ private String title;
+ private String content;
+ private String time;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public void setTime(String time) {
+ this.time = time;
+ }
+}
diff --git a/src/main/java/com/example/entity/Question.java b/src/main/java/com/example/entity/Question.java
new file mode 100644
index 0000000..23cf3c8
--- /dev/null
+++ b/src/main/java/com/example/entity/Question.java
@@ -0,0 +1,153 @@
+package com.example.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Question {
+ private Integer id;
+ private String name;
+ private Integer courseId;
+ private Integer teacherId;
+ private Integer typeId;
+ private String optionA;
+ private String optionB;
+ private String optionC;
+ private String optionD;
+ private String answer;
+
+ private String courseName;
+ private String teacherName;
+ private String typeName;
+ private Integer typeScore;
+
+ private String newAnswer;
+ private List checkList = new ArrayList<>();
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getCourseId() {
+ return courseId;
+ }
+
+ public void setCourseId(Integer courseId) {
+ this.courseId = courseId;
+ }
+
+ public Integer getTeacherId() {
+ return teacherId;
+ }
+
+ public void setTeacherId(Integer teacherId) {
+ this.teacherId = teacherId;
+ }
+
+ public Integer getTypeId() {
+ return typeId;
+ }
+
+ public void setTypeId(Integer typeId) {
+ this.typeId = typeId;
+ }
+
+ public String getOptionA() {
+ return optionA;
+ }
+
+ public void setOptionA(String optionA) {
+ this.optionA = optionA;
+ }
+
+ public String getOptionB() {
+ return optionB;
+ }
+
+ public void setOptionB(String optionB) {
+ this.optionB = optionB;
+ }
+
+ public String getOptionC() {
+ return optionC;
+ }
+
+ public void setOptionC(String optionC) {
+ this.optionC = optionC;
+ }
+
+ public String getOptionD() {
+ return optionD;
+ }
+
+ public void setOptionD(String optionD) {
+ this.optionD = optionD;
+ }
+
+ public String getAnswer() {
+ return answer;
+ }
+
+ public void setAnswer(String answer) {
+ this.answer = answer;
+ }
+
+ public String getCourseName() {
+ return courseName;
+ }
+
+ public void setCourseName(String courseName) {
+ this.courseName = courseName;
+ }
+
+ public String getTeacherName() {
+ return teacherName;
+ }
+
+ public void setTeacherName(String teacherName) {
+ this.teacherName = teacherName;
+ }
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public void setTypeName(String typeName) {
+ this.typeName = typeName;
+ }
+
+ public Integer getTypeScore() {
+ return typeScore;
+ }
+
+ public void setTypeScore(Integer typeScore) {
+ this.typeScore = typeScore;
+ }
+
+ public String getNewAnswer() {
+ return newAnswer;
+ }
+
+ public void setNewAnswer(String newAnswer) {
+ this.newAnswer = newAnswer;
+ }
+
+ public List getCheckList() {
+ return checkList;
+ }
+
+ public void setCheckList(List checkList) {
+ this.checkList = checkList;
+ }
+}
diff --git a/src/main/java/com/example/entity/QuestionType.java b/src/main/java/com/example/entity/QuestionType.java
new file mode 100644
index 0000000..6ababc6
--- /dev/null
+++ b/src/main/java/com/example/entity/QuestionType.java
@@ -0,0 +1,31 @@
+package com.example.entity;
+
+public class QuestionType {
+ private Integer id;
+ private String name;
+ private Integer score;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getScore() {
+ return score;
+ }
+
+ public void setScore(Integer score) {
+ this.score = score;
+ }
+}
diff --git a/src/main/java/com/example/entity/Score.java b/src/main/java/com/example/entity/Score.java
new file mode 100644
index 0000000..d41455b
--- /dev/null
+++ b/src/main/java/com/example/entity/Score.java
@@ -0,0 +1,135 @@
+package com.example.entity;
+
+import java.util.List;
+
+public class Score {
+ private Integer id;
+ private String name;
+ private Integer courseId;
+ private Integer teacherId;
+ private Integer studentId;
+ private Integer paperId;
+ private Integer score;
+ private String status;
+ private String answer;
+
+ private String courseName;
+ private String teacherName;
+ private String studentName;
+
+ private List questions;
+ private List answerData;
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getCourseId() {
+ return courseId;
+ }
+
+ public void setCourseId(Integer courseId) {
+ this.courseId = courseId;
+ }
+
+ public Integer getTeacherId() {
+ return teacherId;
+ }
+
+ public void setTeacherId(Integer teacherId) {
+ this.teacherId = teacherId;
+ }
+
+ public Integer getStudentId() {
+ return studentId;
+ }
+
+ public void setStudentId(Integer studentId) {
+ this.studentId = studentId;
+ }
+
+ public Integer getPaperId() {
+ return paperId;
+ }
+
+ public void setPaperId(Integer paperId) {
+ this.paperId = paperId;
+ }
+
+ public Integer getScore() {
+ return score;
+ }
+
+ public void setScore(Integer score) {
+ this.score = score;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getAnswer() {
+ return answer;
+ }
+
+ public void setAnswer(String answer) {
+ this.answer = answer;
+ }
+
+ public String getCourseName() {
+ return courseName;
+ }
+
+ public void setCourseName(String courseName) {
+ this.courseName = courseName;
+ }
+
+ public String getTeacherName() {
+ return teacherName;
+ }
+
+ public void setTeacherName(String teacherName) {
+ this.teacherName = teacherName;
+ }
+
+ public String getStudentName() {
+ return studentName;
+ }
+
+ public void setStudentName(String studentName) {
+ this.studentName = studentName;
+ }
+
+ public List getQuestions() {
+ return questions;
+ }
+
+ public void setQuestions(List questions) {
+ this.questions = questions;
+ }
+
+ public List getAnswerData() {
+ return answerData;
+ }
+
+ public void setAnswerData(List answerData) {
+ this.answerData = answerData;
+ }
+}
diff --git a/src/main/java/com/example/entity/Student.java b/src/main/java/com/example/entity/Student.java
new file mode 100644
index 0000000..bd0a748
--- /dev/null
+++ b/src/main/java/com/example/entity/Student.java
@@ -0,0 +1,88 @@
+package com.example.entity;
+
+public class Student extends Account {
+
+ /** 主键ID */
+ private Integer id;
+ /** 账号 */
+ private String username;
+ private String password;
+ private String name;
+ private String avatar;
+ private String role;
+ private String phone;
+ private String email;
+ private String status;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+}
diff --git a/src/main/java/com/example/entity/Teacher.java b/src/main/java/com/example/entity/Teacher.java
new file mode 100644
index 0000000..fcc44a3
--- /dev/null
+++ b/src/main/java/com/example/entity/Teacher.java
@@ -0,0 +1,79 @@
+package com.example.entity;
+
+public class Teacher extends Account {
+
+ /** 主键ID */
+ private Integer id;
+ /** 账号 */
+ private String username;
+ private String password;
+ private String name;
+ private String avatar;
+ private String role;
+ private String phone;
+ private String email;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+}
diff --git a/src/main/java/com/example/entity/TestPaper.java b/src/main/java/com/example/entity/TestPaper.java
new file mode 100644
index 0000000..11ca4a2
--- /dev/null
+++ b/src/main/java/com/example/entity/TestPaper.java
@@ -0,0 +1,210 @@
+package com.example.entity;
+
+import java.util.List;
+
+public class TestPaper {
+ // 数据库的基本字段
+ private Integer id;
+ private String name;
+ private Integer courseId;
+ private Integer teacherId;
+ private String type;
+ private String start;
+ private String end;
+ private Integer time;
+ private String questionIds; // 保存该试卷所有的题目的id的json字符串: "[1,2,3,4,5]"
+
+ // 关联课程信息表和教师信息表查询的额外的字段信息
+ private String courseName;
+ private String courseImg;
+ private String teacherName;
+ private String teacherAvatar;
+ private String status;
+
+ // 用来接收前台那边传过来的业务字段
+ private List idList; // 接收前台那边手动选题选中的所有的题目的id
+ private Integer choiceNum; // 接收前台那边自动组卷填写的单选题的数量
+ private Integer multiChoiceNum; // 接收前台那边自动组卷填写的多选题的数量
+ private Integer fillInNum; // 接收前台那边自动组卷填写的填空题的数量
+ private Integer checkNum; // 接收前台那边自动组卷填写的判断题的数量
+ private Integer answerNum; // 接收前台那边自动组卷填写的简答题的数量
+
+ private List questions;
+ private Integer maxTime; // 存储时长(秒)
+
+ public List getQuestions() {
+ return questions;
+ }
+
+ public void setQuestions(List questions) {
+ this.questions = questions;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getCourseId() {
+ return courseId;
+ }
+
+ public void setCourseId(Integer courseId) {
+ this.courseId = courseId;
+ }
+
+ public Integer getTeacherId() {
+ return teacherId;
+ }
+
+ public void setTeacherId(Integer teacherId) {
+ this.teacherId = teacherId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getStart() {
+ return start;
+ }
+
+ public void setStart(String start) {
+ this.start = start;
+ }
+
+ public String getEnd() {
+ return end;
+ }
+
+ public void setEnd(String end) {
+ this.end = end;
+ }
+
+ public Integer getTime() {
+ return time;
+ }
+
+ public void setTime(Integer time) {
+ this.time = time;
+ }
+
+ public String getQuestionIds() {
+ return questionIds;
+ }
+
+ public void setQuestionIds(String questionIds) {
+ this.questionIds = questionIds;
+ }
+
+ public String getCourseName() {
+ return courseName;
+ }
+
+ public void setCourseName(String courseName) {
+ this.courseName = courseName;
+ }
+
+ public String getCourseImg() {
+ return courseImg;
+ }
+
+ public void setCourseImg(String courseImg) {
+ this.courseImg = courseImg;
+ }
+
+ public String getTeacherName() {
+ return teacherName;
+ }
+
+ public void setTeacherName(String teacherName) {
+ this.teacherName = teacherName;
+ }
+
+ public String getTeacherAvatar() {
+ return teacherAvatar;
+ }
+
+ public void setTeacherAvatar(String teacherAvatar) {
+ this.teacherAvatar = teacherAvatar;
+ }
+
+ public List getIdList() {
+ return idList;
+ }
+
+ public void setIdList(List idList) {
+ this.idList = idList;
+ }
+
+ public Integer getChoiceNum() {
+ return choiceNum;
+ }
+
+ public void setChoiceNum(Integer choiceNum) {
+ this.choiceNum = choiceNum;
+ }
+
+ public Integer getMultiChoiceNum() {
+ return multiChoiceNum;
+ }
+
+ public void setMultiChoiceNum(Integer multiChoiceNum) {
+ this.multiChoiceNum = multiChoiceNum;
+ }
+
+ public Integer getFillInNum() {
+ return fillInNum;
+ }
+
+ public void setFillInNum(Integer fillInNum) {
+ this.fillInNum = fillInNum;
+ }
+
+ public Integer getCheckNum() {
+ return checkNum;
+ }
+
+ public void setCheckNum(Integer checkNum) {
+ this.checkNum = checkNum;
+ }
+
+ public Integer getAnswerNum() {
+ return answerNum;
+ }
+
+ public void setAnswerNum(Integer answerNum) {
+ this.answerNum = answerNum;
+ }
+
+ public Integer getMaxTime() {
+ return maxTime;
+ }
+
+ public void setMaxTime(Integer maxTime) {
+ this.maxTime = maxTime;
+ }
+}
diff --git a/src/main/java/com/example/exception/CustomException.java b/src/main/java/com/example/exception/CustomException.java
new file mode 100644
index 0000000..4388f75
--- /dev/null
+++ b/src/main/java/com/example/exception/CustomException.java
@@ -0,0 +1,35 @@
+package com.example.exception;
+
+import com.example.common.enums.ResultCodeEnum;
+
+public class CustomException extends RuntimeException {
+
+ private String code;
+ private String msg;
+
+ public CustomException(String code, String msg) {
+ this.code = code;
+ this.msg = msg;
+ }
+
+ public CustomException(ResultCodeEnum resultCodeEnum) {
+ this.code = resultCodeEnum.code;
+ this.msg = resultCodeEnum.msg;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+}
diff --git a/src/main/java/com/example/exception/GlobalExceptionHandler.java b/src/main/java/com/example/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..eb89d17
--- /dev/null
+++ b/src/main/java/com/example/exception/GlobalExceptionHandler.java
@@ -0,0 +1,28 @@
+package com.example.exception;
+
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
+import com.example.common.Result;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@ControllerAdvice("com.example.controller")
+public class GlobalExceptionHandler {
+
+ private static final Log log = LogFactory.get();
+
+ @ExceptionHandler(Exception.class)
+ @ResponseBody // 返回json串
+ public Result error(Exception e) {
+ log.error("异常信息:", e);
+ return Result.error();
+ }
+
+ @ExceptionHandler(CustomException.class)
+ @ResponseBody // 返回json串
+ public Result error(CustomException e) {
+// log.error("异常信息:", e);
+ return Result.error(e.getCode(), e.getMsg());
+ }
+}
diff --git a/src/main/java/com/example/mapper/AdminMapper.java b/src/main/java/com/example/mapper/AdminMapper.java
new file mode 100644
index 0000000..1b678ce
--- /dev/null
+++ b/src/main/java/com/example/mapper/AdminMapper.java
@@ -0,0 +1,24 @@
+package com.example.mapper;
+
+import com.example.entity.Admin;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface AdminMapper {
+
+ int insert(Admin admin);
+
+ void updateById(Admin admin);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `admin` where id = #{id}")
+ Admin selectById(Integer id);
+
+ @Select("select * from `admin` where username = #{username}")
+ Admin selectByUsername(String username);
+
+ List selectAll(Admin admin);
+
+}
diff --git a/src/main/java/com/example/mapper/ArticleMapper.java b/src/main/java/com/example/mapper/ArticleMapper.java
new file mode 100644
index 0000000..4af508d
--- /dev/null
+++ b/src/main/java/com/example/mapper/ArticleMapper.java
@@ -0,0 +1,23 @@
+package com.example.mapper;
+
+import com.example.entity.Article;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface ArticleMapper {
+
+ int insert(Article article);
+
+ void updateById(Article article);
+
+ void deleteById(Integer id);
+
+ @Select("select article.*, student.name as studentName from `article` " +
+ "left join student on article.student_id = student.id " +
+ "where article.id = #{id}")
+ Article selectById(Integer id);
+
+ List selectAll(Article article);
+
+}
diff --git a/src/main/java/com/example/mapper/CourseMapper.java b/src/main/java/com/example/mapper/CourseMapper.java
new file mode 100644
index 0000000..6041d1d
--- /dev/null
+++ b/src/main/java/com/example/mapper/CourseMapper.java
@@ -0,0 +1,21 @@
+package com.example.mapper;
+
+import com.example.entity.Course;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface CourseMapper {
+
+ int insert(Course course);
+
+ void updateById(Course course);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `course` where id = #{id}")
+ Course selectById(Integer id);
+
+ List selectAll(Course course);
+
+}
diff --git a/src/main/java/com/example/mapper/ExamPlanMapper.java b/src/main/java/com/example/mapper/ExamPlanMapper.java
new file mode 100644
index 0000000..9bc8bfb
--- /dev/null
+++ b/src/main/java/com/example/mapper/ExamPlanMapper.java
@@ -0,0 +1,21 @@
+package com.example.mapper;
+
+import com.example.entity.ExamPlan;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface ExamPlanMapper {
+
+ int insert(ExamPlan examPlan);
+
+ void updateById(ExamPlan examPlan);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `examPlan` where id = #{id}")
+ ExamPlan selectById(Integer id);
+
+ List selectAll(ExamPlan examPlan);
+
+}
diff --git a/src/main/java/com/example/mapper/NoticeMapper.java b/src/main/java/com/example/mapper/NoticeMapper.java
new file mode 100644
index 0000000..3e19f0d
--- /dev/null
+++ b/src/main/java/com/example/mapper/NoticeMapper.java
@@ -0,0 +1,21 @@
+package com.example.mapper;
+
+import com.example.entity.Notice;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface NoticeMapper {
+
+ int insert(Notice notice);
+
+ void updateById(Notice notice);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `notice` where id = #{id}")
+ Notice selectById(Integer id);
+
+ List selectAll(Notice notice);
+
+}
diff --git a/src/main/java/com/example/mapper/QuestionMapper.java b/src/main/java/com/example/mapper/QuestionMapper.java
new file mode 100644
index 0000000..28cee45
--- /dev/null
+++ b/src/main/java/com/example/mapper/QuestionMapper.java
@@ -0,0 +1,26 @@
+package com.example.mapper;
+
+import com.example.entity.Question;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface QuestionMapper {
+
+ int insert(Question question);
+
+ void updateById(Question question);
+
+ void deleteById(Integer id);
+
+ @Select("select question.*, question_type.score as typeScore, question_type.name as typeName from `question` " +
+ "left join question_type on question.type_id = question_type.id " +
+ "where question.id = #{id}")
+ Question selectById(Integer id);
+
+ List selectAll(Question question);
+
+ @Select("select * from question where course_id = #{courseId} and type_id = #{typeId}")
+ List selectByCouserIdAndTypeId(@Param("courseId") Integer courseId, @Param("typeId") Integer typeId);
+}
diff --git a/src/main/java/com/example/mapper/QuestionTypeMapper.java b/src/main/java/com/example/mapper/QuestionTypeMapper.java
new file mode 100644
index 0000000..0d7e6c5
--- /dev/null
+++ b/src/main/java/com/example/mapper/QuestionTypeMapper.java
@@ -0,0 +1,23 @@
+package com.example.mapper;
+
+import com.example.entity.QuestionType;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface QuestionTypeMapper {
+
+ int insert(QuestionType questionType);
+
+ void updateById(QuestionType questionType);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `question_type` where id = #{id}")
+ QuestionType selectById(Integer id);
+
+ List selectAll(QuestionType questionType);
+
+ @Select("select * from question_type where name = #{name}")
+ List selectByName(String name);
+}
diff --git a/src/main/java/com/example/mapper/ScoreMapper.java b/src/main/java/com/example/mapper/ScoreMapper.java
new file mode 100644
index 0000000..e618941
--- /dev/null
+++ b/src/main/java/com/example/mapper/ScoreMapper.java
@@ -0,0 +1,21 @@
+package com.example.mapper;
+
+import com.example.entity.Score;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface ScoreMapper {
+
+ int insert(Score score);
+
+ void updateById(Score score);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `score` where id = #{id}")
+ Score selectById(Integer id);
+
+ List selectAll(Score score);
+
+}
diff --git a/src/main/java/com/example/mapper/StudentMapper.java b/src/main/java/com/example/mapper/StudentMapper.java
new file mode 100644
index 0000000..57f2b12
--- /dev/null
+++ b/src/main/java/com/example/mapper/StudentMapper.java
@@ -0,0 +1,24 @@
+package com.example.mapper;
+
+import com.example.entity.Student;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface StudentMapper {
+
+ int insert(Student student);
+
+ void updateById(Student student);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `student` where id = #{id}")
+ Student selectById(Integer id);
+
+ @Select("select * from `student` where username = #{username}")
+ Student selectByUsername(String username);
+
+ List selectAll(Student student);
+
+}
diff --git a/src/main/java/com/example/mapper/TeacherMapper.java b/src/main/java/com/example/mapper/TeacherMapper.java
new file mode 100644
index 0000000..c2abf69
--- /dev/null
+++ b/src/main/java/com/example/mapper/TeacherMapper.java
@@ -0,0 +1,24 @@
+package com.example.mapper;
+
+import com.example.entity.Teacher;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface TeacherMapper {
+
+ int insert(Teacher teacher);
+
+ void updateById(Teacher teacher);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `teacher` where id = #{id}")
+ Teacher selectById(Integer id);
+
+ @Select("select * from `teacher` where username = #{username}")
+ Teacher selectByUsername(String username);
+
+ List selectAll(Teacher teacher);
+
+}
diff --git a/src/main/java/com/example/mapper/TestPaperMapper.java b/src/main/java/com/example/mapper/TestPaperMapper.java
new file mode 100644
index 0000000..07414e9
--- /dev/null
+++ b/src/main/java/com/example/mapper/TestPaperMapper.java
@@ -0,0 +1,21 @@
+package com.example.mapper;
+
+import com.example.entity.TestPaper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+public interface TestPaperMapper {
+
+ int insert(TestPaper testPaper);
+
+ void updateById(TestPaper testPaper);
+
+ void deleteById(Integer id);
+
+ @Select("select * from `test_paper` where id = #{id}")
+ TestPaper selectById(Integer id);
+
+ List selectAll(TestPaper testPaper);
+
+}
diff --git a/src/main/java/com/example/service/AdminService.java b/src/main/java/com/example/service/AdminService.java
new file mode 100644
index 0000000..0b25130
--- /dev/null
+++ b/src/main/java/com/example/service/AdminService.java
@@ -0,0 +1,103 @@
+package com.example.service;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.example.common.Constants;
+import com.example.common.enums.ResultCodeEnum;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.entity.Admin;
+import com.example.exception.CustomException;
+import com.example.mapper.AdminMapper;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 业务层方法
+ */
+@Service
+public class AdminService {
+
+ @Resource
+ private AdminMapper adminMapper;
+
+ public void add(Admin admin) {
+ Admin dbAdmin = adminMapper.selectByUsername(admin.getUsername());
+ if (ObjectUtil.isNotNull(dbAdmin)) {
+ throw new CustomException(ResultCodeEnum.USER_EXIST_ERROR);
+ }
+ if (ObjectUtil.isEmpty(admin.getPassword())) {
+ admin.setPassword(Constants.USER_DEFAULT_PASSWORD);
+ }
+ if (ObjectUtil.isEmpty(admin.getName())) {
+ admin.setName(admin.getUsername());
+ }
+ admin.setRole(RoleEnum.ADMIN.name());
+ adminMapper.insert(admin);
+ }
+
+ public void updateById(Admin admin) {
+ adminMapper.updateById(admin);
+ }
+
+ public void deleteById(Integer id) {
+ adminMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ adminMapper.deleteById(id);
+ }
+ }
+
+ public Admin selectById(Integer id) {
+ return adminMapper.selectById(id);
+ }
+
+ public List selectAll(Admin admin) {
+ return adminMapper.selectAll(admin);
+ }
+
+ public PageInfo selectPage(Admin admin, Integer pageNum, Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List list = adminMapper.selectAll(admin);
+ return PageInfo.of(list);
+ }
+
+ /**
+ * 登录
+ */
+ public Admin login(Account account) {
+ Admin dbAdmin = adminMapper.selectByUsername(account.getUsername());
+ if (ObjectUtil.isNull(dbAdmin)) {
+ throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
+ }
+ if (!dbAdmin.getPassword().equals(account.getPassword())) {
+ throw new CustomException(ResultCodeEnum.USER_ACCOUNT_ERROR);
+ }
+ // 生成token
+ String token = TokenUtils.createToken(dbAdmin.getId() + "-" + dbAdmin.getRole(), dbAdmin.getPassword());
+ dbAdmin.setToken(token);
+ return dbAdmin;
+ }
+
+ /**
+ * 修改密码
+ */
+ public void updatePassword(Account account) {
+ Admin dbAdmin = adminMapper.selectByUsername(account.getUsername());
+ if (ObjectUtil.isNull(dbAdmin)) {
+ throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
+ }
+ if (!account.getPassword().equals(dbAdmin.getPassword())) {
+ throw new CustomException(ResultCodeEnum.PARAM_PASSWORD_ERROR);
+ }
+ dbAdmin.setPassword(account.getNewPassword());
+ adminMapper.updateById(dbAdmin);
+ }
+
+}
diff --git a/src/main/java/com/example/service/ArticleService.java b/src/main/java/com/example/service/ArticleService.java
new file mode 100644
index 0000000..bdc2330
--- /dev/null
+++ b/src/main/java/com/example/service/ArticleService.java
@@ -0,0 +1,68 @@
+package com.example.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.example.entity.Account;
+import com.example.entity.Article;
+import com.example.mapper.ArticleMapper;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 帖子信息业务层方法
+ */
+@Service
+public class ArticleService {
+
+ @Resource
+ private ArticleMapper articleMapper;
+
+ public void add(Article article) {
+ Account currentUser = TokenUtils.getCurrentUser();
+ article.setStudentId(currentUser.getId());
+ article.setTime(DateUtil.now());
+ articleMapper.insert(article);
+ }
+
+ public void updateById(Article article) {
+ articleMapper.updateById(article);
+ }
+
+ public void deleteById(Integer id) {
+ articleMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ articleMapper.deleteById(id);
+ }
+ }
+
+ public Article selectById(Integer id) {
+ return articleMapper.selectById(id);
+ }
+
+ public List selectAll(Article article) {
+ return articleMapper.selectAll(article);
+ }
+
+ public PageInfo selectPage(Article article, Integer pageNum, Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List list = articleMapper.selectAll(article);
+ return PageInfo.of(list);
+ }
+
+ public List selectRandom() {
+ List list = articleMapper.selectAll(new Article());
+ Collections.shuffle(list);
+ if (list.size() > 3) {
+ return list.subList(0, 3);
+ }
+ return list;
+ }
+}
diff --git a/src/main/java/com/example/service/CourseService.java b/src/main/java/com/example/service/CourseService.java
new file mode 100644
index 0000000..f536df1
--- /dev/null
+++ b/src/main/java/com/example/service/CourseService.java
@@ -0,0 +1,63 @@
+package com.example.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.entity.Course;
+import com.example.mapper.CourseMapper;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 课程信息业务层方法
+ */
+@Service
+public class CourseService {
+
+ @Resource
+ private CourseMapper courseMapper;
+
+ public void add(Course course) {
+ Account currentUser = TokenUtils.getCurrentUser();
+ course.setTeacherId(currentUser.getId());
+ courseMapper.insert(course);
+ }
+
+ public void updateById(Course course) {
+ courseMapper.updateById(course);
+ }
+
+ public void deleteById(Integer id) {
+ courseMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ courseMapper.deleteById(id);
+ }
+ }
+
+ public Course selectById(Integer id) {
+ return courseMapper.selectById(id);
+ }
+
+ public List selectAll(Course course) {
+ return courseMapper.selectAll(course);
+ }
+
+ public PageInfo selectPage(Course course, Integer pageNum, Integer pageSize) {
+ Account currentUser = TokenUtils.getCurrentUser();
+ if (RoleEnum.TEACHER.name().equals(currentUser.getRole())) {
+ course.setTeacherId(currentUser.getId());
+ }
+ PageHelper.startPage(pageNum, pageSize);
+ List list = courseMapper.selectAll(course);
+ return PageInfo.of(list);
+ }
+
+}
diff --git a/src/main/java/com/example/service/ExamPlanService.java b/src/main/java/com/example/service/ExamPlanService.java
new file mode 100644
index 0000000..e675f0c
--- /dev/null
+++ b/src/main/java/com/example/service/ExamPlanService.java
@@ -0,0 +1,55 @@
+package com.example.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.example.entity.ExamPlan;
+import com.example.mapper.ExamPlanMapper;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 考试安排业务层方法
+ */
+@Service
+public class ExamPlanService {
+
+ @Resource
+ private ExamPlanMapper examPlanMapper;
+
+ public void add(ExamPlan examPlan) {
+ examPlan.setTime(DateUtil.now());
+ examPlanMapper.insert(examPlan);
+ }
+
+ public void updateById(ExamPlan examPlan) {
+ examPlanMapper.updateById(examPlan);
+ }
+
+ public void deleteById(Integer id) {
+ examPlanMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ examPlanMapper.deleteById(id);
+ }
+ }
+
+ public ExamPlan selectById(Integer id) {
+ return examPlanMapper.selectById(id);
+ }
+
+ public List selectAll(ExamPlan examPlan) {
+ return examPlanMapper.selectAll(examPlan);
+ }
+
+ public PageInfo selectPage(ExamPlan examPlan, Integer pageNum, Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List list = examPlanMapper.selectAll(examPlan);
+ return PageInfo.of(list);
+ }
+
+}
diff --git a/src/main/java/com/example/service/NoticeService.java b/src/main/java/com/example/service/NoticeService.java
new file mode 100644
index 0000000..9fc72d9
--- /dev/null
+++ b/src/main/java/com/example/service/NoticeService.java
@@ -0,0 +1,55 @@
+package com.example.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.example.entity.Notice;
+import com.example.mapper.NoticeMapper;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 业务层方法
+ */
+@Service
+public class NoticeService {
+
+ @Resource
+ private NoticeMapper noticeMapper;
+
+ public void add(Notice notice) {
+ notice.setTime(DateUtil.now());
+ noticeMapper.insert(notice);
+ }
+
+ public void updateById(Notice notice) {
+ noticeMapper.updateById(notice);
+ }
+
+ public void deleteById(Integer id) {
+ noticeMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ noticeMapper.deleteById(id);
+ }
+ }
+
+ public Notice selectById(Integer id) {
+ return noticeMapper.selectById(id);
+ }
+
+ public List selectAll(Notice notice) {
+ return noticeMapper.selectAll(notice);
+ }
+
+ public PageInfo selectPage(Notice notice, Integer pageNum, Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List list = noticeMapper.selectAll(notice);
+ return PageInfo.of(list);
+ }
+
+}
diff --git a/src/main/java/com/example/service/QuestionService.java b/src/main/java/com/example/service/QuestionService.java
new file mode 100644
index 0000000..9a08166
--- /dev/null
+++ b/src/main/java/com/example/service/QuestionService.java
@@ -0,0 +1,63 @@
+package com.example.service;
+
+import cn.hutool.core.date.DateUtil;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.entity.Question;
+import com.example.mapper.QuestionMapper;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 题目信息业务层方法
+ */
+@Service
+public class QuestionService {
+
+ @Resource
+ private QuestionMapper questionMapper;
+
+ public void add(Question question) {
+ Account currentUser = TokenUtils.getCurrentUser();
+ question.setTeacherId(currentUser.getId());
+ questionMapper.insert(question);
+ }
+
+ public void updateById(Question question) {
+ questionMapper.updateById(question);
+ }
+
+ public void deleteById(Integer id) {
+ questionMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ questionMapper.deleteById(id);
+ }
+ }
+
+ public Question selectById(Integer id) {
+ return questionMapper.selectById(id);
+ }
+
+ public List selectAll(Question question) {
+ return questionMapper.selectAll(question);
+ }
+
+ public PageInfo selectPage(Question question, Integer pageNum, Integer pageSize) {
+ Account currentUser = TokenUtils.getCurrentUser();
+ if (RoleEnum.TEACHER.name().equals(currentUser.getRole())) {
+ question.setTeacherId(currentUser.getId());
+ }
+ PageHelper.startPage(pageNum, pageSize);
+ List list = questionMapper.selectAll(question);
+ return PageInfo.of(list);
+ }
+
+}
diff --git a/src/main/java/com/example/service/QuestionTypeService.java b/src/main/java/com/example/service/QuestionTypeService.java
new file mode 100644
index 0000000..9a14619
--- /dev/null
+++ b/src/main/java/com/example/service/QuestionTypeService.java
@@ -0,0 +1,66 @@
+package com.example.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import com.example.entity.QuestionType;
+import com.example.exception.CustomException;
+import com.example.mapper.QuestionTypeMapper;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 题型信息业务层方法
+ */
+@Service
+public class QuestionTypeService {
+
+ @Resource
+ private QuestionTypeMapper questionTypeMapper;
+
+ public void add(QuestionType questionType) {
+ // 同一题型不能被重复添加
+ List list = questionTypeMapper.selectByName(questionType.getName());
+ if (CollectionUtil.isNotEmpty(list)) {
+ throw new CustomException("-1", "题型名称不能重复");
+ }
+ questionTypeMapper.insert(questionType);
+ }
+
+ public void updateById(QuestionType questionType) {
+ // 同一题型不能被重复添加
+ List list = questionTypeMapper.selectByName(questionType.getName());
+ if (CollectionUtil.isNotEmpty(list) && !questionType.getId().equals(list.get(0).getId())) {
+ throw new CustomException("-1", "题型名称不能重复");
+ }
+ questionTypeMapper.updateById(questionType);
+ }
+
+ public void deleteById(Integer id) {
+ questionTypeMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ questionTypeMapper.deleteById(id);
+ }
+ }
+
+ public QuestionType selectById(Integer id) {
+ return questionTypeMapper.selectById(id);
+ }
+
+ public List selectAll(QuestionType questionType) {
+ return questionTypeMapper.selectAll(questionType);
+ }
+
+ public PageInfo selectPage(QuestionType questionType, Integer pageNum, Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List list = questionTypeMapper.selectAll(questionType);
+ return PageInfo.of(list);
+ }
+
+}
diff --git a/src/main/java/com/example/service/ScoreService.java b/src/main/java/com/example/service/ScoreService.java
new file mode 100644
index 0000000..259c201
--- /dev/null
+++ b/src/main/java/com/example/service/ScoreService.java
@@ -0,0 +1,165 @@
+package com.example.service;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.*;
+import com.example.mapper.QuestionMapper;
+import com.example.mapper.ScoreMapper;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 成绩信息业务层方法
+ */
+@Service
+public class ScoreService {
+
+ @Resource
+ private ScoreMapper scoreMapper;
+ @Resource
+ private QuestionMapper questionMapper;
+
+ public void add(TestPaper testPaper) {
+
+ // 封装一下用户提交的试卷信息
+ List list = new ArrayList<>();
+ for (Question question : testPaper.getQuestions()) {
+ Answer answer = new Answer();
+ answer.setTypeName(question.getTypeName());
+ answer.setScore(question.getTypeScore());
+ answer.setQuestionId(question.getId());
+ if ("多选题".equals(question.getTypeName())) {
+ List checkList = question.getCheckList();
+ answer.setNewAnswer(String.join(",", checkList));
+ } else {
+ answer.setNewAnswer(question.getNewAnswer());
+ }
+ answer.setAnswer(question.getAnswer());
+ list.add(answer);
+ }
+
+ Score score = new Score();
+ Account currentUser = TokenUtils.getCurrentUser();
+ score.setStudentId(currentUser.getId());
+ score.setTeacherId(testPaper.getTeacherId());
+ score.setCourseId(testPaper.getCourseId());
+ score.setName(testPaper.getName());
+ score.setPaperId(testPaper.getId());
+ score.setStatus("待阅卷");
+ score.setAnswer(JSONUtil.toJsonStr(list));
+ scoreMapper.insert(score);
+ }
+
+ public void updateById(Score score) {
+ List answerData = score.getAnswerData();
+ int total = 0;
+ for (Answer answer : answerData) {
+ if (ObjectUtil.isNotEmpty(answer.getResult())) {
+ total += answer.getResult();
+ }
+ }
+ score.setScore(total);
+ score.setAnswer(JSONUtil.toJsonStr(answerData));
+ score.setStatus("已阅卷");
+ scoreMapper.updateById(score);
+ }
+
+ public void deleteById(Integer id) {
+ scoreMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ scoreMapper.deleteById(id);
+ }
+ }
+
+ public Score selectById(Integer id) {
+ List scores = scoreMapper.selectAll(new Score());
+ Score score = scores.stream().filter(x -> x.getId().equals(id)).findFirst().get();
+ String answer = score.getAnswer();
+ List list = JSONUtil.toList(answer, Answer.class);
+
+ List questions = new ArrayList<>();
+ for (Answer ans : list) {
+ Question question = questionMapper.selectById(ans.getQuestionId());
+ if (ObjectUtil.isNotEmpty(question)) {
+ if ("多选题".equals(ans.getTypeName())) {
+ String newAnswer = ans.getNewAnswer(); // A,B,C
+ List checkList = Arrays.asList(newAnswer.split(","));
+ question.setCheckList(checkList);
+ } else {
+ question.setNewAnswer(ans.getNewAnswer());
+ }
+ questions.add(question);
+ }
+ }
+ score.setQuestions(questions);
+ return score;
+ }
+
+ public List selectAll(Score score) {
+ return scoreMapper.selectAll(score);
+ }
+
+ public PageInfo selectPage(Score score, Integer pageNum, Integer pageSize) {
+ Account currentUser = TokenUtils.getCurrentUser();
+ if (RoleEnum.STUDENT.name().equals(currentUser.getRole())) {
+ score.setStudentId(currentUser.getId());
+ }
+ if (RoleEnum.TEACHER.name().equals(currentUser.getRole())) {
+ score.setTeacherId(currentUser.getId());
+ }
+ PageHelper.startPage(pageNum, pageSize);
+ List list = scoreMapper.selectAll(score);
+ return PageInfo.of(list);
+ }
+
+ public List selectAnswer(Integer id) {
+ Score score = scoreMapper.selectById(id);
+ List list = JSONUtil.toList(score.getAnswer(), Answer.class);
+ // 客观题自动阅卷功能
+ for (Answer answer : list) {
+ Question question = questionMapper.selectById(answer.getQuestionId());
+ answer.setQuestionName(question.getName());
+ // 客观题自动打分
+ if (!"简答题".equals(answer.getTypeName())) {
+ if (!"多选题".equals(answer.getTypeName())) {
+ if (answer.getAnswer().equals(answer.getNewAnswer())) {
+ answer.setResult(answer.getScore());
+ } else {
+ answer.setResult(0);
+ }
+ } else {
+ // 多选题 只要选项都对就行 顺序没有关系: A,B,C 和 B,A,C 是一样的
+ List standardList = Arrays.asList(answer.getAnswer().split(",")); // [A, B, C]
+ List studentList = Arrays.asList(answer.getNewAnswer().split(",")); // [B, A, C]
+ for (String s : standardList) {
+ if (!studentList.contains(s)) {
+ answer.setResult(0);
+ break;
+ }
+ }
+ if (ObjectUtil.isEmpty(answer.getResult())) {
+ if (studentList.size() == standardList.size()) {
+ answer.setResult(answer.getScore());
+ } else {
+ answer.setResult(0);
+ }
+ }
+ }
+ }
+ }
+ return list;
+ }
+}
diff --git a/src/main/java/com/example/service/StudentService.java b/src/main/java/com/example/service/StudentService.java
new file mode 100644
index 0000000..dd2f825
--- /dev/null
+++ b/src/main/java/com/example/service/StudentService.java
@@ -0,0 +1,113 @@
+package com.example.service;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.example.common.Constants;
+import com.example.common.enums.ResultCodeEnum;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.entity.Student;
+import com.example.exception.CustomException;
+import com.example.mapper.StudentMapper;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 学生信息业务层方法
+ */
+@Service
+public class StudentService {
+
+ @Resource
+ private StudentMapper studentMapper;
+
+ public void add(Student student) {
+ Student dbStudent = studentMapper.selectByUsername(student.getUsername());
+ if (ObjectUtil.isNotNull(dbStudent)) {
+ throw new CustomException(ResultCodeEnum.USER_EXIST_ERROR);
+ }
+ if (ObjectUtil.isEmpty(student.getPassword())) {
+ student.setPassword(Constants.USER_DEFAULT_PASSWORD);
+ }
+ if (ObjectUtil.isEmpty(student.getName())) {
+ student.setName(student.getUsername());
+ }
+ student.setRole(RoleEnum.STUDENT.name());
+ student.setStatus("待审核");
+ studentMapper.insert(student);
+ }
+
+ public void updateById(Student student) {
+ studentMapper.updateById(student);
+ }
+
+ public void deleteById(Integer id) {
+ studentMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ studentMapper.deleteById(id);
+ }
+ }
+
+ public Student selectById(Integer id) {
+ return studentMapper.selectById(id);
+ }
+
+ public List selectAll(Student student) {
+ return studentMapper.selectAll(student);
+ }
+
+ public PageInfo selectPage(Student student, Integer pageNum, Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List list = studentMapper.selectAll(student);
+ return PageInfo.of(list);
+ }
+
+ /**
+ * 登录
+ */
+ public Student login(Account account) {
+ Student dbStudent = studentMapper.selectByUsername(account.getUsername());
+ if (ObjectUtil.isNull(dbStudent)) {
+ throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
+ }
+ if (!dbStudent.getPassword().equals(account.getPassword())) {
+ throw new CustomException(ResultCodeEnum.USER_ACCOUNT_ERROR);
+ }
+ if (!"审核通过".equals(dbStudent.getStatus())) {
+ throw new CustomException("-1", "您的注册信息尚未审核通过,暂不允许登录,请耐心等待管理员审核");
+ }
+ // 生成token
+ String token = TokenUtils.createToken(dbStudent.getId() + "-" + dbStudent.getRole(), dbStudent.getPassword());
+ dbStudent.setToken(token);
+ return dbStudent;
+ }
+
+ /**
+ * 修改密码
+ */
+ public void updatePassword(Account account) {
+ Student dbStudent = studentMapper.selectByUsername(account.getUsername());
+ if (ObjectUtil.isNull(dbStudent)) {
+ throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
+ }
+ if (!account.getPassword().equals(dbStudent.getPassword())) {
+ throw new CustomException(ResultCodeEnum.PARAM_PASSWORD_ERROR);
+ }
+ dbStudent.setPassword(account.getNewPassword());
+ studentMapper.updateById(dbStudent);
+ }
+
+ public void register(Account account) {
+ Student student = new Student();
+ BeanUtils.copyProperties(account, student);
+ add(student);
+ }
+}
diff --git a/src/main/java/com/example/service/TeacherService.java b/src/main/java/com/example/service/TeacherService.java
new file mode 100644
index 0000000..b7f4f14
--- /dev/null
+++ b/src/main/java/com/example/service/TeacherService.java
@@ -0,0 +1,109 @@
+package com.example.service;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.example.common.Constants;
+import com.example.common.enums.ResultCodeEnum;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.entity.Teacher;
+import com.example.exception.CustomException;
+import com.example.mapper.TeacherMapper;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 教师信息业务层方法
+ */
+@Service
+public class TeacherService {
+
+ @Resource
+ private TeacherMapper teacherMapper;
+
+ public void add(Teacher teacher) {
+ Teacher dbTeacher = teacherMapper.selectByUsername(teacher.getUsername());
+ if (ObjectUtil.isNotNull(dbTeacher)) {
+ throw new CustomException(ResultCodeEnum.USER_EXIST_ERROR);
+ }
+ if (ObjectUtil.isEmpty(teacher.getPassword())) {
+ teacher.setPassword(Constants.USER_DEFAULT_PASSWORD);
+ }
+ if (ObjectUtil.isEmpty(teacher.getName())) {
+ teacher.setName(teacher.getUsername());
+ }
+ teacher.setRole(RoleEnum.TEACHER.name());
+ teacherMapper.insert(teacher);
+ }
+
+ public void updateById(Teacher teacher) {
+ teacherMapper.updateById(teacher);
+ }
+
+ public void deleteById(Integer id) {
+ teacherMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ teacherMapper.deleteById(id);
+ }
+ }
+
+ public Teacher selectById(Integer id) {
+ return teacherMapper.selectById(id);
+ }
+
+ public List selectAll(Teacher teacher) {
+ return teacherMapper.selectAll(teacher);
+ }
+
+ public PageInfo selectPage(Teacher teacher, Integer pageNum, Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List list = teacherMapper.selectAll(teacher);
+ return PageInfo.of(list);
+ }
+
+ /**
+ * 登录
+ */
+ public Teacher login(Account account) {
+ Teacher dbTeacher = teacherMapper.selectByUsername(account.getUsername());
+ if (ObjectUtil.isNull(dbTeacher)) {
+ throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
+ }
+ if (!dbTeacher.getPassword().equals(account.getPassword())) {
+ throw new CustomException(ResultCodeEnum.USER_ACCOUNT_ERROR);
+ }
+ // 生成token
+ String token = TokenUtils.createToken(dbTeacher.getId() + "-" + dbTeacher.getRole(), dbTeacher.getPassword());
+ dbTeacher.setToken(token);
+ return dbTeacher;
+ }
+
+ /**
+ * 修改密码
+ */
+ public void updatePassword(Account account) {
+ Teacher dbTeacher = teacherMapper.selectByUsername(account.getUsername());
+ if (ObjectUtil.isNull(dbTeacher)) {
+ throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
+ }
+ if (!account.getPassword().equals(dbTeacher.getPassword())) {
+ throw new CustomException(ResultCodeEnum.PARAM_PASSWORD_ERROR);
+ }
+ dbTeacher.setPassword(account.getNewPassword());
+ teacherMapper.updateById(dbTeacher);
+ }
+
+ public void register(Account account) {
+ Teacher teacher = new Teacher();
+ BeanUtils.copyProperties(account, teacher);
+ add(teacher);
+ }
+}
diff --git a/src/main/java/com/example/service/TestPaperService.java b/src/main/java/com/example/service/TestPaperService.java
new file mode 100644
index 0000000..4702829
--- /dev/null
+++ b/src/main/java/com/example/service/TestPaperService.java
@@ -0,0 +1,209 @@
+package com.example.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.*;
+import com.example.exception.CustomException;
+import com.example.mapper.*;
+import com.example.utils.TokenUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 试卷信息业务层方法
+ */
+@Service
+public class TestPaperService {
+
+ @Resource
+ private TestPaperMapper testPaperMapper;
+ @Resource
+ private QuestionMapper questionMapper;
+ @Resource
+ private CourseMapper courseMapper;
+ @Resource
+ private TeacherMapper teacherMapper;
+ @Resource
+ private ScoreMapper scoreMapper;
+
+ public void add(TestPaper testPaper) throws ParseException {
+ // 先要校验前台传过来的数据
+ check(testPaper);
+ Account currentUser = TokenUtils.getCurrentUser();
+ testPaper.setTeacherId(currentUser.getId());
+ // 手动选题
+ if ("手动选题".equals(testPaper.getType())) {
+ List idList = testPaper.getIdList();
+ testPaper.setQuestionIds(JSONUtil.toJsonStr(idList));
+ }
+ if ("自动组卷".equals(testPaper.getType())) {
+ List list = new ArrayList<>();
+ // 自动选取每个题型的题目
+ randomQuestionIds(testPaper, testPaper.getChoiceNum(), list, 1, "单选题");
+ randomQuestionIds(testPaper, testPaper.getMultiChoiceNum(), list, 2, "多选题");
+ randomQuestionIds(testPaper, testPaper.getCheckNum(), list, 3, "判断题");
+ randomQuestionIds(testPaper, testPaper.getFillInNum(), list, 4, "填空题");
+ randomQuestionIds(testPaper, testPaper.getAnswerNum(), list, 5, "简答题");
+
+ testPaper.setQuestionIds(JSONUtil.toJsonStr(list));
+ }
+
+ testPaperMapper.insert(testPaper);
+ }
+
+ private void randomQuestionIds(TestPaper testPaper, Integer choiceNum, List list, Integer typeId, String typeName) {
+ List choiceList = questionMapper.selectByCouserIdAndTypeId(testPaper.getCourseId(), typeId);
+ if (choiceList.size() < choiceNum) {
+ throw new CustomException("-1", "您的题库里该课程的" + typeName + "数量不足,请减少出题的" + typeName + "数量或者增加题库里该课程的" + typeName + "数量");
+ }
+ Collections.shuffle(choiceList); // 打乱
+ List questions = choiceList.subList(0, choiceNum).stream().map(Question::getId).toList();
+ list.addAll(questions);
+ }
+
+ public void check (TestPaper testPaper) throws ParseException {
+ if (ObjectUtil.isEmpty(testPaper.getName())
+ || ObjectUtil.isEmpty(testPaper.getCourseId())
+ || ObjectUtil.isEmpty(testPaper.getStart())
+ || ObjectUtil.isEmpty(testPaper.getEnd())
+ || ObjectUtil.isEmpty(testPaper.getTime())
+ || ObjectUtil.isEmpty(testPaper.getType())
+ ) {
+ throw new CustomException("-1", "请填写完整您要提交的试卷信息");
+ }
+ // 开始时间要早于结束时间
+ long start = new SimpleDateFormat("yyyy-MM-dd").parse(testPaper.getStart()).getTime();
+ long end = new SimpleDateFormat("yyyy-MM-dd").parse(testPaper.getEnd()).getTime();
+ if (start >= end) {
+ throw new CustomException("-1", "开始时间必须早于结束时间");
+ }
+ // 校验手动选题
+ if ("手动选题".equals(testPaper.getType())) {
+ if (CollectionUtil.isEmpty(testPaper.getIdList())) {
+ throw new CustomException("-1", "手动选题方式,您需要选择具体的题目");
+ }
+ }
+ // 自动组卷校验
+ if ("自动组卷".equals(testPaper.getType())) {
+ if (ObjectUtil.isEmpty(testPaper.getChoiceNum())
+ || ObjectUtil.isEmpty(testPaper.getMultiChoiceNum())
+ || ObjectUtil.isEmpty(testPaper.getFillInNum())
+ || ObjectUtil.isEmpty(testPaper.getCheckNum())
+ || ObjectUtil.isEmpty(testPaper.getAnswerNum())
+ ) {
+ throw new CustomException("-1", "请填写题型的数量,如果不需要某个题型,请输入0");
+ }
+ if (testPaper.getChoiceNum() < 0
+ || testPaper.getMultiChoiceNum() < 0
+ || testPaper.getFillInNum() < 0
+ || testPaper.getCheckNum() < 0
+ || testPaper.getAnswerNum() < 0
+ ) {
+ throw new CustomException("-1", "题型的数量不能小于0");
+ }
+ }
+ }
+
+ public void updateById(TestPaper testPaper) {
+ testPaperMapper.updateById(testPaper);
+ }
+
+ public void deleteById(Integer id) {
+ testPaperMapper.deleteById(id);
+ }
+
+ public void deleteBatch(List ids) {
+ for (Integer id : ids) {
+ testPaperMapper.deleteById(id);
+ }
+ }
+
+ public TestPaper selectById(Integer id) {
+ TestPaper testPaper = testPaperMapper.selectById(id);
+ Course course = courseMapper.selectById(testPaper.getCourseId());
+ if (ObjectUtil.isNotEmpty(course)) {
+ testPaper.setCourseName(course.getName());
+ }
+ Teacher teacher = teacherMapper.selectById(testPaper.getTeacherId());
+ if (ObjectUtil.isNotEmpty(teacher)) {
+ testPaper.setTeacherName(teacher.getName());
+ }
+ // 开始组装该试卷里所有的题目数据
+ String questionIds = testPaper.getQuestionIds();
+ List idList = JSONUtil.toList(questionIds, Integer.class);
+ List questions = new ArrayList<>();
+ for (Integer questionId : idList) {
+ Question question = questionMapper.selectById(questionId);
+ questions.add(question);
+ }
+ testPaper.setQuestions(questions);
+ testPaper.setMaxTime(testPaper.getTime() * 60);
+ return testPaper;
+ }
+
+ public List selectAll(TestPaper testPaper) {
+ return testPaperMapper.selectAll(testPaper);
+ }
+
+ public PageInfo selectPage(TestPaper testPaper, Integer pageNum, Integer pageSize) throws ParseException {
+ Account currentUser = TokenUtils.getCurrentUser();
+ if (RoleEnum.TEACHER.name().equals(currentUser.getRole())) {
+ testPaper.setTeacherId(currentUser.getId());
+ }
+ PageHelper.startPage(pageNum, pageSize);
+ List list = testPaperMapper.selectAll(testPaper);
+ // 初始化每个考试的状态
+ initStatus(list);
+ return PageInfo.of(list);
+ }
+
+ private static void initStatus(List list) throws ParseException {
+ for (TestPaper paper : list) {
+ long now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(DateUtil.now()).getTime();
+ long start = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(paper.getStart() + " 00:00:00").getTime();
+ long end = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(paper.getEnd() + " 23:59:59").getTime();
+ if (now < start) {
+ paper.setStatus("未开始");
+ } else if (now > end) {
+ paper.setStatus("已结束");
+ } else {
+ paper.setStatus("进行中");
+ }
+ }
+ }
+
+ public void checkTestPaper(Integer id) {
+ Account currentUser = TokenUtils.getCurrentUser();
+ Score score = new Score();
+ score.setPaperId(id);
+ score.setStudentId(currentUser.getId());
+ List scores = scoreMapper.selectAll(score);
+ if (CollectionUtil.isNotEmpty(scores)) {
+ throw new CustomException("-1", "该门考试您已经提交过试卷了,入口已关闭");
+ }
+ }
+
+ public List selectRandom() throws ParseException {
+ List list = testPaperMapper.selectAll(new TestPaper());
+ Collections.shuffle(list);
+ // 初始化每个考试的状态
+ initStatus(list);
+ if (list.size() > 4) {
+ return list.subList(0, 4);
+ }
+ return list;
+ }
+}
diff --git a/src/main/java/com/example/utils/TokenUtils.java b/src/main/java/com/example/utils/TokenUtils.java
new file mode 100644
index 0000000..1200379
--- /dev/null
+++ b/src/main/java/com/example/utils/TokenUtils.java
@@ -0,0 +1,84 @@
+package com.example.utils;
+
+import cn.hutool.core.date.DateUtil;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.example.common.Constants;
+import com.example.common.enums.RoleEnum;
+import com.example.entity.Account;
+import com.example.service.AdminService;
+import com.example.service.StudentService;
+import com.example.service.TeacherService;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.Date;
+
+/**
+ * Token工具类
+ */
+@Component
+public class TokenUtils {
+ private static final Logger log = LoggerFactory.getLogger(TokenUtils.class);
+
+ @Resource
+ private AdminService adminService;
+ @Resource
+ private TeacherService teacherService;
+ @Resource
+ private StudentService studentService;
+
+ private static AdminService staticAdminService;
+ private static TeacherService staticTeacherService;
+ private static StudentService staticStudentService;
+
+ @PostConstruct
+ public void init() {
+ staticAdminService = adminService;
+ staticTeacherService = teacherService;
+ staticStudentService = studentService;
+ }
+
+ /**
+ * 生成JWT token
+ */
+ public static String createToken(String data, String sign) {
+ // audience是存储数据的一个媒介 存储用户ID和用户的角色 1-ADMIN
+ return JWT.create().withAudience(data)
+ .withExpiresAt(DateUtil.offsetDay(new Date(), 1)) // 设置过期时间1天后
+ .sign(Algorithm.HMAC256(sign));
+ }
+
+ /**
+ * 获取当前登录的用户
+ */
+ public static Account getCurrentUser() {
+ try {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ String token = request.getHeader(Constants.TOKEN);
+ String audience = JWT.decode(token).getAudience().get(0);
+ String[] userRole = audience.split("-");
+ Integer userId = Integer.valueOf(userRole[0]);
+ String role = userRole[1];
+ if (RoleEnum.ADMIN.name().equals(role)) {
+ return staticAdminService.selectById(userId);
+ }
+ if (RoleEnum.TEACHER.name().equals(role)) {
+ return staticTeacherService.selectById(userId);
+ }
+ if (RoleEnum.STUDENT.name().equals(role)) {
+ return staticStudentService.selectById(userId);
+ }
+ } catch (Exception e) {
+ log.error("获取当前登录用户出错", e);
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..c225a2f
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,19 @@
+server:
+ port: 9090
+
+# 数据库配置
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ username: root
+ password: 123456
+ url: jdbc:mysql://localhost:33060/java-experiment?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true
+
+# 配置mybatis实体和xml映射
+mybatis:
+ configuration:
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ map-underscore-to-camel-case: true
+ mapper-locations: classpath:mapper/*.xml
+
+fileBaseUrl: http://localhost:${server.port}
\ No newline at end of file
diff --git a/src/main/resources/mapper/AdminMapper.xml b/src/main/resources/mapper/AdminMapper.xml
new file mode 100644
index 0000000..6e94c52
--- /dev/null
+++ b/src/main/resources/mapper/AdminMapper.xml
@@ -0,0 +1,71 @@
+
+
+
+
+ select * from `admin`
+
+ and name like concat('%', #{name}, '%')
+
+
+
+
+ delete from `admin`
+ where id = #{id}
+
+
+
+
+ insert into `admin`
+
+ id,
+ username,
+ password,
+ name,
+ phone,
+ email,
+ avatar,
+ role,
+
+
+ #{id},
+ #{username},
+ #{password},
+ #{name},
+ #{phone},
+ #{email},
+ #{avatar},
+ #{role},
+
+
+
+
+ update `admin`
+
+
+ username = #{username},
+
+
+ password = #{password},
+
+
+ name = #{name},
+
+
+ phone = #{phone},
+
+
+ email = #{email},
+
+
+ avatar = #{avatar},
+
+
+ role = #{role},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/ArticleMapper.xml b/src/main/resources/mapper/ArticleMapper.xml
new file mode 100644
index 0000000..2434ebd
--- /dev/null
+++ b/src/main/resources/mapper/ArticleMapper.xml
@@ -0,0 +1,60 @@
+
+
+
+
+ select article.*, student.name as studentName, student.avatar as studentAvatar from `article`
+ left join student on article.student_id = student.id
+
+ and title like concat('%', #{title}, '%')
+ and student_id = #{studentId}
+
+
+
+
+ delete from `article`
+ where id = #{id}
+
+
+
+
+ insert into `article`
+
+ id,
+ title,
+ content,
+ time,
+ img,
+ student_id,
+
+
+ #{id},
+ #{title},
+ #{content},
+ #{time},
+ #{img},
+ #{studentId},
+
+
+
+
+ update `article`
+
+
+ title = #{title},
+
+
+ content = #{content},
+
+
+ time = #{time},
+
+
+ img = #{img},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/CourseMapper.xml b/src/main/resources/mapper/CourseMapper.xml
new file mode 100644
index 0000000..2088dd0
--- /dev/null
+++ b/src/main/resources/mapper/CourseMapper.xml
@@ -0,0 +1,55 @@
+
+
+
+
+ select course.*, teacher.name as teacherName from `course`
+ left join teacher on course.teacher_id = teacher.id
+
+ and course.name like concat('%', #{name}, '%')
+ and teacher_id = #{teacherId}
+
+
+
+
+ delete from `course`
+ where id = #{id}
+
+
+
+
+ insert into `course`
+
+ id,
+ name,
+ img,
+ score,
+ teacher_id,
+
+
+ #{id},
+ #{name},
+ #{img},
+ #{score},
+ #{teacherId},
+
+
+
+
+ update `course`
+
+
+ name = #{name},
+
+
+ img = #{img},
+
+
+ score = #{score},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/ExamPlanMapper.xml b/src/main/resources/mapper/ExamPlanMapper.xml
new file mode 100644
index 0000000..9224b64
--- /dev/null
+++ b/src/main/resources/mapper/ExamPlanMapper.xml
@@ -0,0 +1,51 @@
+
+
+
+
+ select * from `exam_plan`
+
+ and title like concat('%', #{title}, '%')
+
+
+
+
+ delete from `exam_plan`
+ where id = #{id}
+
+
+
+
+ insert into `exam_plan`
+
+ id,
+ title,
+ content,
+ time,
+
+
+ #{id},
+ #{title},
+ #{content},
+ #{time},
+
+
+
+
+ update `exam_plan`
+
+
+ title = #{title},
+
+
+ content = #{content},
+
+
+ time = #{time},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/NoticeMapper.xml b/src/main/resources/mapper/NoticeMapper.xml
new file mode 100644
index 0000000..4cc8682
--- /dev/null
+++ b/src/main/resources/mapper/NoticeMapper.xml
@@ -0,0 +1,51 @@
+
+
+
+
+ select * from `notice`
+
+ and title like concat('%', #{title}, '%')
+
+
+
+
+ delete from `notice`
+ where id = #{id}
+
+
+
+
+ insert into `notice`
+
+ id,
+ title,
+ content,
+ time,
+
+
+ #{id},
+ #{title},
+ #{content},
+ #{time},
+
+
+
+
+ update `notice`
+
+
+ title = #{title},
+
+
+ content = #{content},
+
+
+ time = #{time},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/QuestionMapper.xml b/src/main/resources/mapper/QuestionMapper.xml
new file mode 100644
index 0000000..15b68d2
--- /dev/null
+++ b/src/main/resources/mapper/QuestionMapper.xml
@@ -0,0 +1,86 @@
+
+
+
+
+ select
+ question.*, course.name as courseName, teacher.name as teacherName,
+ question_type.name as typeName, question_type.score as typeScore
+ from `question`
+ left join course on question.course_id = course.id
+ left join teacher on question.teacher_id = teacher.id
+ left join question_type on question.type_id = question_type.id
+
+ and question.name like concat('%', #{name}, '%')
+ and question.teacher_id = #{teacherId}
+ and question.course_id = #{courseId}
+
+
+
+
+ delete from `question`
+ where id = #{id}
+
+
+
+
+ insert into `question`
+
+ id,
+ name,
+ course_id,
+ teacher_id,
+ type_id,
+ option_a,
+ option_b,
+ option_c,
+ option_d,
+ answer,
+
+
+ #{id},
+ #{name},
+ #{courseId},
+ #{teacherId},
+ #{typeId},
+ #{optionA},
+ #{optionB},
+ #{optionC},
+ #{optionD},
+ #{answer},
+
+
+
+
+ update `question`
+
+
+ name = #{name},
+
+
+ course_id = #{courseId},
+
+
+ type_id = #{typeId},
+
+
+ option_a = #{optionA},
+
+
+ option_b = #{optionB},
+
+
+ option_c = #{optionC},
+
+
+ option_d = #{optionD},
+
+
+ answer = #{answer},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/QuestionTypeMapper.xml b/src/main/resources/mapper/QuestionTypeMapper.xml
new file mode 100644
index 0000000..9079013
--- /dev/null
+++ b/src/main/resources/mapper/QuestionTypeMapper.xml
@@ -0,0 +1,46 @@
+
+
+
+
+ select * from `question_type`
+
+ and name like concat('%', #{name}, '%')
+
+
+
+
+ delete from `question_type`
+ where id = #{id}
+
+
+
+
+ insert into `question_type`
+
+ id,
+ name,
+ score,
+
+
+ #{id},
+ #{name},
+ #{score},
+
+
+
+
+ update `question_type`
+
+
+ name = #{name},
+
+
+ score = #{score},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/ScoreMapper.xml b/src/main/resources/mapper/ScoreMapper.xml
new file mode 100644
index 0000000..c0214c4
--- /dev/null
+++ b/src/main/resources/mapper/ScoreMapper.xml
@@ -0,0 +1,66 @@
+
+
+
+
+ select score.*, course.name as courseName, teacher.name as teacherName, student.name as studentName from `score`
+ left join course on score.course_id = course.id
+ left join teacher on score.teacher_id = teacher.id
+ left join student on score.student_id = student.id
+
+ and score.name like concat('%', #{name}, '%')
+ and score.student_id = #{studentId}
+ and score.teacher_id = #{teacherId}
+ and score.paper_id = #{paperId}
+ and course.name like concat('%', #{courseName}, '%')
+ and score.status = #{status}
+
+
+
+
+ delete from `score`
+ where id = #{id}
+
+
+
+
+ insert into `score`
+
+ id,
+ name,
+ course_id,
+ teacher_id,
+ student_id,
+ paper_id,
+ score,
+ status,
+ answer,
+
+
+ #{id},
+ #{name},
+ #{courseId},
+ #{teacherId},
+ #{studentId},
+ #{paperId},
+ #{score},
+ #{status},
+ #{answer},
+
+
+
+
+ update `score`
+
+
+ score = #{score},
+
+
+ status = #{status},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/StudentMapper.xml b/src/main/resources/mapper/StudentMapper.xml
new file mode 100644
index 0000000..b573368
--- /dev/null
+++ b/src/main/resources/mapper/StudentMapper.xml
@@ -0,0 +1,76 @@
+
+
+
+
+ select * from `student`
+
+ and name like concat('%', #{name}, '%')
+
+
+
+
+ delete from `student`
+ where id = #{id}
+
+
+
+
+ insert into `student`
+
+ id,
+ username,
+ password,
+ name,
+ phone,
+ email,
+ avatar,
+ role,
+ status,
+
+
+ #{id},
+ #{username},
+ #{password},
+ #{name},
+ #{phone},
+ #{email},
+ #{avatar},
+ #{role},
+ #{status},
+
+
+
+
+ update `student`
+
+
+ username = #{username},
+
+
+ password = #{password},
+
+
+ name = #{name},
+
+
+ phone = #{phone},
+
+
+ email = #{email},
+
+
+ avatar = #{avatar},
+
+
+ role = #{role},
+
+
+ status = #{status},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/TeacherMapper.xml b/src/main/resources/mapper/TeacherMapper.xml
new file mode 100644
index 0000000..c459aa5
--- /dev/null
+++ b/src/main/resources/mapper/TeacherMapper.xml
@@ -0,0 +1,71 @@
+
+
+
+
+ select * from `teacher`
+
+ and name like concat('%', #{name}, '%')
+
+
+
+
+ delete from `teacher`
+ where id = #{id}
+
+
+
+
+ insert into `teacher`
+
+ id,
+ username,
+ password,
+ name,
+ phone,
+ email,
+ avatar,
+ role,
+
+
+ #{id},
+ #{username},
+ #{password},
+ #{name},
+ #{phone},
+ #{email},
+ #{avatar},
+ #{role},
+
+
+
+
+ update `teacher`
+
+
+ username = #{username},
+
+
+ password = #{password},
+
+
+ name = #{name},
+
+
+ phone = #{phone},
+
+
+ email = #{email},
+
+
+ avatar = #{avatar},
+
+
+ role = #{role},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mapper/TestPaperMapper.xml b/src/main/resources/mapper/TestPaperMapper.xml
new file mode 100644
index 0000000..cbac808
--- /dev/null
+++ b/src/main/resources/mapper/TestPaperMapper.xml
@@ -0,0 +1,61 @@
+
+
+
+
+ select test_paper.*, course.name as courseName, course.img as courseImg,
+ teacher.name as teacherName, teacher.avatar as teacherAvatar
+ from `test_paper`
+ left join course on test_paper.course_id = course.id
+ left join teacher on test_paper.teacher_id = teacher.id
+
+ and test_paper.name like concat('%', #{name}, '%')
+ and test_paper.teacher_id = #{teacherId}
+ and course.name like concat('%', #{courseName}, '%')
+
+
+
+
+ delete from `test_paper`
+ where id = #{id}
+
+
+
+
+ insert into `test_paper`
+
+ id,
+ name,
+ course_id,
+ teacher_id,
+ type,
+ start,
+ end,
+ time,
+ question_ids,
+
+
+ #{id},
+ #{name},
+ #{courseId},
+ #{teacherId},
+ #{type},
+ #{start},
+ #{end},
+ #{time},
+ #{questionIds},
+
+
+
+
+ update `test_paper`
+
+
+ name = #{name},
+
+
+ where id = #{id}
+
+
+
\ No newline at end of file
diff --git a/ui/.env.development b/ui/.env.development
new file mode 100644
index 0000000..62bb4ac
--- /dev/null
+++ b/ui/.env.development
@@ -0,0 +1 @@
+VITE_BASE_URL='http://localhost:9090'
\ No newline at end of file
diff --git a/ui/.env.production b/ui/.env.production
new file mode 100644
index 0000000..2beb7d1
--- /dev/null
+++ b/ui/.env.production
@@ -0,0 +1 @@
+VITE_BASE_URL='http://:9090'
\ No newline at end of file
diff --git a/ui/.gitignore b/ui/.gitignore
new file mode 100644
index 0000000..c6660fa
--- /dev/null
+++ b/ui/.gitignore
@@ -0,0 +1,28 @@
+# ---> Java
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
+
+.idea
+node_modules
diff --git a/ui/index.html b/ui/index.html
new file mode 100644
index 0000000..b3dc0fe
--- /dev/null
+++ b/ui/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ 在线考试系统
+
+
+
+
+
+
diff --git a/ui/jsconfig.json b/ui/jsconfig.json
new file mode 100644
index 0000000..5a1f2d2
--- /dev/null
+++ b/ui/jsconfig.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/ui/package.json b/ui/package.json
new file mode 100644
index 0000000..c8c45c3
--- /dev/null
+++ b/ui/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "vue",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@element-plus/icons-vue": "^2.3.1",
+ "@wangeditor/editor": "^5.1.23",
+ "@wangeditor/editor-for-vue": "^5.1.12",
+ "axios": "^1.7.2",
+ "element-plus": "^2.7.6",
+ "vue": "^3.4.29",
+ "vue-router": "^4.3.3"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.0.5",
+ "sass": "^1.89.0",
+ "unplugin-auto-import": "^0.17.6",
+ "unplugin-element-plus": "^0.8.0",
+ "unplugin-vue-components": "^0.27.2",
+ "vite": "^5.3.1"
+ }
+}
diff --git a/ui/public/favicon.ico b/ui/public/favicon.ico
new file mode 100644
index 0000000..eafa13b
Binary files /dev/null and b/ui/public/favicon.ico differ
diff --git a/ui/src/App.vue b/ui/src/App.vue
new file mode 100644
index 0000000..6d11557
--- /dev/null
+++ b/ui/src/App.vue
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ui/src/assets/css/front.css b/ui/src/assets/css/front.css
new file mode 100644
index 0000000..1425567
--- /dev/null
+++ b/ui/src/assets/css/front.css
@@ -0,0 +1,57 @@
+.front-notice {
+ padding: 5px 20px;
+ color: #666;
+ font-size: 12px;
+ display: flex;
+ align-items: center;
+}
+
+.front-header {
+ display: flex;
+ height: 60px;
+ line-height: 60px;
+ border-bottom: 1px solid #eee;
+}
+
+.front-header-left {
+ width: 350px;
+ display: flex;
+ align-items: center;
+ padding-left: 30px;
+}
+
+.front-header-left img {
+ width: 35px;
+ height: 35px;
+ border-radius: 50%;
+}
+
+.front-header-left .title {
+ color: #333;
+ cursor: pointer;
+ margin-left: 10px;
+ font-size: 20px;
+ font-weight: bold;
+}
+
+.front-header-center {
+ flex: 1;
+}
+
+.front-header-right {
+ padding-right: 20px;
+}
+
+.main-content {
+ width: 80%;
+ margin: 5px auto;
+}
+
+/*Element-Plus样式覆盖*/
+.el-menu--horizontal {
+ border: none !important;
+ height: 59px;
+}
+.el-tooltip__trigger {
+ outline: none;
+}
\ No newline at end of file
diff --git a/ui/src/assets/css/global.css b/ui/src/assets/css/global.css
new file mode 100644
index 0000000..ee8e02b
--- /dev/null
+++ b/ui/src/assets/css/global.css
@@ -0,0 +1,21 @@
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ color: #333;
+ font-size: 14px;
+}
+
+a {
+ text-decoration: none;
+}
+
+.card {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 10px;
+ box-shadow: 0 0 10px rgba(0,0,0,.1);
+}
\ No newline at end of file
diff --git a/ui/src/assets/css/index.scss b/ui/src/assets/css/index.scss
new file mode 100644
index 0000000..f8162aa
--- /dev/null
+++ b/ui/src/assets/css/index.scss
@@ -0,0 +1,7 @@
+@forward "element-plus/theme-chalk/src/common/var.scss" with ($colors: (
+ "primary": ("base": #1baf8a),
+ "success": ("base": #46b61f),
+ "warning": ("base": #f1cf61),
+ "danger": ("base": #e52f2f),
+ "info": ("base": #7d83d5),
+));
diff --git a/ui/src/assets/css/manager.css b/ui/src/assets/css/manager.css
new file mode 100644
index 0000000..2305801
--- /dev/null
+++ b/ui/src/assets/css/manager.css
@@ -0,0 +1,108 @@
+.manager-container {
+ background-color: #f8f8ff;
+ min-height: 100vh;
+}
+
+.manager-header {
+ height: 60px;
+ background-color: #07c796;
+ display: flex;
+ align-items: center;
+ box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
+}
+
+.manager-header-left {
+ background-color: #07c796;
+ width: 250px;
+ height: 100%;
+ padding-left: 10px;
+ display: flex;
+ align-items: center
+}
+
+.manager-header-left img {
+ width: 30px;
+ height: 30px;
+}
+
+.manager-header-left .title {
+ font-weight: bold;
+ font-size: 20px;
+ margin-left: 10px;
+ color: #eee;
+}
+
+.manager-header-center {
+ flex: 1;
+ padding-left: 20px;
+}
+
+.manager-main-left {
+ width: 200px;
+ background-color: #fff;
+ min-height: calc(100vh - 60px);
+ box-shadow: 0 0 6px rgba(0, 21, 41, .35);
+}
+
+.manager-main-right {
+ flex: 1;
+ width: 0;
+ background-color: #f8f8ff;
+ padding: 10px;
+}
+
+
+/* ElementUI */
+.el-menu {
+ border: none;
+ background-color: #fff;
+}
+
+.el-tooltip__trigger {
+ outline: none;
+}
+
+/deep/.el-sub-menu__title {
+ color: #666 !important;
+ height: 50px;
+ line-height: 50px;
+ background-color: #fff !important;
+}
+
+.el-sub-menu__title:hover {
+ background-color: #fff; /* 必须加上这个背景色,否则鼠标移入会出现白色 */
+ color: #fff;
+}
+
+.el-menu-item {
+ color: #666;
+ height: 50px;
+ line-height: 50px;
+ background-color: #fff !important; /* 必须加上这个背景色,否则鼠标离开会出现白色 */
+}
+
+.el-menu--inline .el-menu-item {
+ background-color: #fff !important;
+}
+
+.el-menu-item.is-active {
+ background-color: #cdf4ea !important;
+ color: #07c796;
+ border-right: 3px solid #07c796;
+}
+
+.el-menu-item:not(.is-active):hover {
+ color: #fff;
+}
+.el-menu-item:hover {
+ background-color: #e6f9f5 !important;
+ color: #07c796 !important;
+}
+
+/deep/.el-breadcrumb__inner {
+ color: white !important;
+}
+
+/deep/.manager-header-right span {
+ color: white;
+}
diff --git a/ui/src/assets/imgs/404.jpg b/ui/src/assets/imgs/404.jpg
new file mode 100644
index 0000000..7ce045c
Binary files /dev/null and b/ui/src/assets/imgs/404.jpg differ
diff --git a/ui/src/assets/imgs/avatar.png b/ui/src/assets/imgs/avatar.png
new file mode 100644
index 0000000..e16488e
Binary files /dev/null and b/ui/src/assets/imgs/avatar.png differ
diff --git a/ui/src/assets/imgs/bg.jpg b/ui/src/assets/imgs/bg.jpg
new file mode 100644
index 0000000..4df0a9b
Binary files /dev/null and b/ui/src/assets/imgs/bg.jpg differ
diff --git a/ui/src/assets/imgs/carousel-1.jpg b/ui/src/assets/imgs/carousel-1.jpg
new file mode 100644
index 0000000..53c9ea6
Binary files /dev/null and b/ui/src/assets/imgs/carousel-1.jpg differ
diff --git a/ui/src/assets/imgs/carousel-2.jpg b/ui/src/assets/imgs/carousel-2.jpg
new file mode 100644
index 0000000..5db5eef
Binary files /dev/null and b/ui/src/assets/imgs/carousel-2.jpg differ
diff --git a/ui/src/assets/imgs/carousel-3.jpg b/ui/src/assets/imgs/carousel-3.jpg
new file mode 100644
index 0000000..275d60d
Binary files /dev/null and b/ui/src/assets/imgs/carousel-3.jpg differ
diff --git a/ui/src/assets/imgs/logo.png b/ui/src/assets/imgs/logo.png
new file mode 100644
index 0000000..eafa13b
Binary files /dev/null and b/ui/src/assets/imgs/logo.png differ
diff --git a/ui/src/main.js b/ui/src/main.js
new file mode 100644
index 0000000..3bf9304
--- /dev/null
+++ b/ui/src/main.js
@@ -0,0 +1,19 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+import '@/assets/css/global.css'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import zhCn from 'element-plus/es/locale/lang/zh-cn'
+
+const app = createApp(App)
+
+app.use(router)
+app.use(ElementPlus, { locale: zhCn })
+app.mount('#app')
+
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
+
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+ app.component(key, component)
+}
diff --git a/ui/src/router/index.js b/ui/src/router/index.js
new file mode 100644
index 0000000..6edb019
--- /dev/null
+++ b/ui/src/router/index.js
@@ -0,0 +1,49 @@
+import { createRouter, createWebHistory } from 'vue-router'
+
+const router = createRouter({
+ history: createWebHistory(import.meta.env.BASE_URL),
+ routes: [
+ { path: '/', redirect: '/manager/home' },
+ {
+ path: '/manager',
+ component: () => import('@/views/Manager.vue'),
+ children: [
+ { path: 'home', meta: { name: '系统首页' }, component: () => import('@/views/manager/Home.vue'), },
+ { path: 'admin', meta: { name: '管理员信息' }, component: () => import('@/views/manager/Admin.vue'), },
+ { path: 'notice', meta: { name: '系统公告' }, component: () => import('@/views/manager/Notice.vue'), },
+ { path: 'person', meta: { name: '个人资料' }, component: () => import('@/views/manager/Person.vue'), },
+ { path: 'password', meta: { name: '修改密码' }, component: () => import('@/views/manager/Password.vue'), },
+ { path: 'teacher', meta: { name: '教师信息' }, component: () => import('@/views/manager/Teacher.vue'), },
+ { path: 'student', meta: { name: '学生信息' }, component: () => import('@/views/manager/Student.vue'), },
+ { path: 'examPlan', meta: { name: '考试安排' }, component: () => import('@/views/manager/ExamPlan.vue'), },
+ { path: 'questionType', meta: { name: '题型信息' }, component: () => import('@/views/manager/QuestionType.vue'), },
+ { path: 'course', meta: { name: '课程信息' }, component: () => import('@/views/manager/Course.vue'), },
+ { path: 'question', meta: { name: '题库信息' }, component: () => import('@/views/manager/Question.vue'), },
+ { path: 'share', meta: { name: '交流分享' }, component: () => import('@/views/manager/Share.vue'), },
+ { path: 'testPaper', meta: { name: '交流分享' }, component: () => import('@/views/manager/TestPaper.vue'), },
+ { path: 'score', meta: { name: '交流分享' }, component: () => import('@/views/manager/Score.vue'), },
+ ]
+ },
+ {
+ path: '/front',
+ component: () => import('@/views/Front.vue'),
+ children: [
+ { path: 'home', component: () => import('@/views/front/Home.vue'), },
+ { path: 'person', component: () => import('@/views/front/Person.vue'), },
+ { path: 'myShare', component: () => import('@/views/front/MyShare.vue'), },
+ { path: 'forum', component: () => import('@/views/front/Forum.vue'), },
+ { path: 'forumDetail', component: () => import('@/views/front/ForumDetail.vue'), },
+ { path: 'exam', component: () => import('@/views/front/Exam.vue'), },
+ { path: 'testPaper', component: () => import('@/views/front/TestPaper.vue'), },
+ { path: 'testPaperView', component: () => import('@/views/front/TestPaperView.vue'), },
+ { path: 'score', component: () => import('@/views/front/Score.vue'), },
+ ]
+ },
+ { path: '/login', component: () => import('@/views/Login.vue') },
+ { path: '/register', component: () => import('@/views/Register.vue') },
+ { path: '/404', component: () => import('@/views/404.vue') },
+ { path: '/:pathMatch(.*)', redirect: '/404' }
+ ]
+})
+
+export default router
diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js
new file mode 100644
index 0000000..f200aff
--- /dev/null
+++ b/ui/src/utils/request.js
@@ -0,0 +1,53 @@
+import axios from "axios";
+import {ElMessage} from "element-plus";
+import router from "@/router/index.js";
+
+const request = axios.create({
+ baseURL: import.meta.env.VITE_BASE_URL,
+ timeout: 30000 // 后台接口超时时间
+})
+
+// request 拦截器
+// 可以自请求发送前对请求做一些处理
+request.interceptors.request.use(config => {
+ config.headers['Content-Type'] = 'application/json;charset=utf-8';
+ let user = JSON.parse(localStorage.getItem("xm-user") || '{}')
+ config.headers['token'] = user.token || ''
+ return config
+}, error => {
+ return Promise.reject(error)
+});
+
+// response 拦截器
+// 可以在接口响应后统一处理结果
+request.interceptors.response.use(
+ response => {
+ let res = response.data;
+ // 如果是返回的文件
+ if (response.config.responseType === 'blob') {
+ return res
+ }
+ // 当权限验证不通过的时候给出提示
+ if (res.code === '401') {
+ ElMessage.error(res.msg)
+ router.push('/login')
+ }
+ // 兼容服务端返回的字符串数据
+ if (typeof res === 'string') {
+ res = res ? JSON.parse(res) : res
+ }
+ return res;
+ },
+ error => {
+ if (error.response.status === 404) {
+ ElMessage.error('未找到请求接口')
+ } else if (error.response.status === 500) {
+ ElMessage.error('系统异常,请查看后端控制台报错')
+ } else {
+ console.error(error.message)
+ }
+ return Promise.reject(error)
+ }
+)
+
+export default request
diff --git a/ui/src/views/404.vue b/ui/src/views/404.vue
new file mode 100644
index 0000000..3e9868b
--- /dev/null
+++ b/ui/src/views/404.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
+
找不到页面啦!请返回主页
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/Front.vue b/ui/src/views/Front.vue
new file mode 100644
index 0000000..0570621
--- /dev/null
+++ b/ui/src/views/Front.vue
@@ -0,0 +1,86 @@
+
+
+
公告:{{ data.top }}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/Login.vue b/ui/src/views/Login.vue
new file mode 100644
index 0000000..88d40f0
--- /dev/null
+++ b/ui/src/views/Login.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
欢迎登录在线考试系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 登 录
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/Manager.vue b/ui/src/views/Manager.vue
new file mode 100644
index 0000000..bb55884
--- /dev/null
+++ b/ui/src/views/Manager.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+ 系统首页
+
+
+
+
+ 信息管理
+
+ 系统公告
+ 考试安排
+ 题型信息
+ 课程信息
+ 题库信息
+ 试卷信息
+
+ {{ data.user.role === 'ADMIN' ? '成绩管理' : '阅卷打分'}}
+
+ 交流分享
+
+
+
+
+ 用户管理
+
+ 管理员信息
+ 教师信息
+ 学生信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/Register.vue b/ui/src/views/Register.vue
new file mode 100644
index 0000000..63f69aa
--- /dev/null
+++ b/ui/src/views/Register.vue
@@ -0,0 +1,103 @@
+
+
+
+
欢 迎 注 册
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 注 册
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/Exam.vue b/ui/src/views/front/Exam.vue
new file mode 100644
index 0000000..230fc87
--- /dev/null
+++ b/ui/src/views/front/Exam.vue
@@ -0,0 +1,91 @@
+
+
+
+
+ 查询
+
+
+
+
+
+
+
{{ item.name }}
+
+
+
{{ item.teacherName }}
+
+ {{ item.status }}
+ {{ item.status }}
+ {{ item.status }}
+
+
+
课程名称:{{ item.courseName }}
+
开放时间:{{ item.start }} ~ {{ item.end }}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/Forum.vue b/ui/src/views/front/Forum.vue
new file mode 100644
index 0000000..642a71b
--- /dev/null
+++ b/ui/src/views/front/Forum.vue
@@ -0,0 +1,71 @@
+
+
+
+
+ 查询
+
+
+
+
+
+
+
{{ item.title }}
+
+
+
{{ item.studentName }}
+
{{ item.time }}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/ForumDetail.vue b/ui/src/views/front/ForumDetail.vue
new file mode 100644
index 0000000..e49b96e
--- /dev/null
+++ b/ui/src/views/front/ForumDetail.vue
@@ -0,0 +1,35 @@
+
+
+
{{ data.articleData.title }}
+
+ 发布人:{{ data.articleData.studentName }}
+ 发布时间:{{ data.articleData.time }}
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/Home.vue b/ui/src/views/front/Home.vue
new file mode 100644
index 0000000..09c980b
--- /dev/null
+++ b/ui/src/views/front/Home.vue
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ item.name }}
+
+
+
{{ item.teacherName }}
+
+ {{ item.status }}
+ {{ item.status }}
+ {{ item.status }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ item.title }}
+
+
+
{{ item.studentName }}
+
{{ item.time }}
+
+
+
+
+
+
+
+
+
+
+ {{ data.form.content }}
+ 发布时间:{{ data.form.time }}
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/MyShare.vue b/ui/src/views/front/MyShare.vue
new file mode 100644
index 0000000..3c6c1dd
--- /dev/null
+++ b/ui/src/views/front/MyShare.vue
@@ -0,0 +1,198 @@
+
+
+
+
我分享的学习经验({{ data.tableData.length }})
+
发布学习经验
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击预览
+
+
+
+
+
+ 编辑
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+ 上传封面
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/Person.vue b/ui/src/views/front/Person.vue
new file mode 100644
index 0000000..e6c93e2
--- /dev/null
+++ b/ui/src/views/front/Person.vue
@@ -0,0 +1,158 @@
+
+
+
+ 修改密码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保 存
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/Score.vue b/ui/src/views/front/Score.vue
new file mode 100644
index 0000000..3cb0a41
--- /dev/null
+++ b/ui/src/views/front/Score.vue
@@ -0,0 +1,60 @@
+
+
+
我的考试({{ data.tableData.length }})
+
+
+
+
+
+
+
+ {{ scope.row.status }}
+ {{ scope.row.status }}
+
+
+
+
+
+ 查看试卷
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/TestPaper.vue b/ui/src/views/front/TestPaper.vue
new file mode 100644
index 0000000..8e04b9b
--- /dev/null
+++ b/ui/src/views/front/TestPaper.vue
@@ -0,0 +1,123 @@
+
+
+
{{ data.testPaperData.name }}
+
+ 课程名称:{{ data.testPaperData.courseName }}
+ 授课教师:{{ data.testPaperData.teacherName }}
+ 考试时间:{{ data.testPaperData.time }} 分钟
+
+
+ 考试倒计时:{{ data.hour }} 时:{{ data.minutes }} 分:{{ data.seconds }} 秒
+
+
+
+
+ {{ item.name }}({{ item.typeScore }} 分)
+
+
+
+
+
+ A. {{ item.optionA }}
+ B. {{ item.optionB }}
+ C. {{ item.optionC }}
+ D. {{ item.optionD }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A. 正确
+ B. 错误
+
+
+
+
+
+
+
+
+
+
+
+
+ 提交试卷
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/front/TestPaperView.vue b/ui/src/views/front/TestPaperView.vue
new file mode 100644
index 0000000..3796cf3
--- /dev/null
+++ b/ui/src/views/front/TestPaperView.vue
@@ -0,0 +1,90 @@
+
+
+
{{ data.testPaperData.name }}
+
+ 课程名称:{{ data.testPaperData.courseName }}
+ 授课教师:{{ data.testPaperData.teacherName }}
+
+
+
+
+ {{ item.name }}({{ item.typeScore }} 分)
+
+
+
+
+
+ A. {{ item.optionA }}
+ B. {{ item.optionB }}
+ C. {{ item.optionC }}
+ D. {{ item.optionD }}
+
+
标准答案:{{ item.answer }}
+
+
+
+
+
+
+
+
+
+
标准答案:{{ item.answer }}
+
+
+
+
+ A. 正确
+ B. 错误
+
+
标准答案:{{ item.answer }}
+
+
+
+
+
标准答案:{{ item.answer }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Admin.vue b/ui/src/views/manager/Admin.vue
new file mode 100644
index 0000000..4233a18
--- /dev/null
+++ b/ui/src/views/manager/Admin.vue
@@ -0,0 +1,187 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击上传
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Course.vue b/ui/src/views/manager/Course.vue
new file mode 100644
index 0000000..4a1d5a0
--- /dev/null
+++ b/ui/src/views/manager/Course.vue
@@ -0,0 +1,182 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 上传封面
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/ExamPlan.vue b/ui/src/views/manager/ExamPlan.vue
new file mode 100644
index 0000000..9ae1045
--- /dev/null
+++ b/ui/src/views/manager/ExamPlan.vue
@@ -0,0 +1,159 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Home.vue b/ui/src/views/manager/Home.vue
new file mode 100644
index 0000000..b77acd3
--- /dev/null
+++ b/ui/src/views/manager/Home.vue
@@ -0,0 +1,71 @@
+
+
+
您好!{{ data.user?.name }},欢迎使用本系统!
+
+
+
系统公告
+
+
+ {{ item.content }}
+
+
+
+
+
考试安排
+
+
+ {{ item.content }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Notice.vue b/ui/src/views/manager/Notice.vue
new file mode 100644
index 0000000..6572b2f
--- /dev/null
+++ b/ui/src/views/manager/Notice.vue
@@ -0,0 +1,159 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Password.vue b/ui/src/views/manager/Password.vue
new file mode 100644
index 0000000..65325f8
--- /dev/null
+++ b/ui/src/views/manager/Password.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保 存
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Person.vue b/ui/src/views/manager/Person.vue
new file mode 100644
index 0000000..646882d
--- /dev/null
+++ b/ui/src/views/manager/Person.vue
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保 存
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Question.vue b/ui/src/views/manager/Question.vue
new file mode 100644
index 0000000..f3f4cfc
--- /dev/null
+++ b/ui/src/views/manager/Question.vue
@@ -0,0 +1,254 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.typeName }}
+ {{ scope.row.typeName }}
+ {{ scope.row.typeName }}
+ {{ scope.row.typeName }}
+ {{ scope.row.typeName }}
+
+
+
+
+
+ 无
+
+
A. {{ scope.row.optionA }}
+
B. {{ scope.row.optionB }}
+
C. {{ scope.row.optionC }}
+
D. {{ scope.row.optionD }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/QuestionType.vue b/ui/src/views/manager/QuestionType.vue
new file mode 100644
index 0000000..9e4bcac
--- /dev/null
+++ b/ui/src/views/manager/QuestionType.vue
@@ -0,0 +1,160 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Score.vue b/ui/src/views/manager/Score.vue
new file mode 100644
index 0000000..639f1e5
--- /dev/null
+++ b/ui/src/views/manager/Score.vue
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.status }}
+ {{ scope.row.status }}
+
+
+
+
+
+ 阅卷
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.answer }}
+
+
+
+
+
+ {{ scope.row.newAnswer }}
+
+
+
+
+
+ {{ scope.row.result }}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Share.vue b/ui/src/views/manager/Share.vue
new file mode 100644
index 0000000..15dda7f
--- /dev/null
+++ b/ui/src/views/manager/Share.vue
@@ -0,0 +1,106 @@
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击预览
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Student.vue b/ui/src/views/manager/Student.vue
new file mode 100644
index 0000000..7e20dea
--- /dev/null
+++ b/ui/src/views/manager/Student.vue
@@ -0,0 +1,201 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.status }}
+ {{ scope.row.status }}
+ {{ scope.row.status }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击上传
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/Teacher.vue b/ui/src/views/manager/Teacher.vue
new file mode 100644
index 0000000..98ebfd0
--- /dev/null
+++ b/ui/src/views/manager/Teacher.vue
@@ -0,0 +1,187 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 新增
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击上传
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/src/views/manager/TestPaper.vue b/ui/src/views/manager/TestPaper.vue
new file mode 100644
index 0000000..a311513
--- /dev/null
+++ b/ui/src/views/manager/TestPaper.vue
@@ -0,0 +1,252 @@
+
+
+
+
+ 查询
+ 重置
+
+
+ 出卷
+ 批量删除
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.type }}
+ {{ scope.row.type }}
+
+
+
+
+
+
+ {{ scope.row.time }} 分钟
+
+
+
+
+ {{ scope.row.status }}
+ {{ scope.row.status }}
+ {{ scope.row.status }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/vite.config.js b/ui/vite.config.js
new file mode 100644
index 0000000..9f8d580
--- /dev/null
+++ b/ui/vite.config.js
@@ -0,0 +1,103 @@
+import { fileURLToPath, URL } from 'node:url'
+
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import AutoImport from 'unplugin-auto-import/vite'
+import Components from 'unplugin-vue-components/vite'
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
+import ElementPlus from 'unplugin-element-plus/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ vue(),
+ // 按需定制主题配置
+ ElementPlus({
+ useSource: true,
+ }),
+ AutoImport({
+ resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
+ }),
+ Components({
+ resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
+ }),
+ ],
+ // 预加载项目必需的组件
+ optimizeDeps: {
+ include: [
+ "vue",
+ "vue-router",
+ "axios",
+ "element-plus/es/components/base/style/css",
+ "element-plus/es/components/message/style/css",
+ "element-plus/es/components/message-box/style/css",
+ "element-plus/es/components/form/style/css",
+ "element-plus/es/components/form-item/style/css",
+ "element-plus/es/components/button/style/css",
+ "element-plus/es/components/input/style/css",
+ "element-plus/es/components/input-number/style/css",
+ "element-plus/es/components/switch/style/css",
+ "element-plus/es/components/upload/style/css",
+ "element-plus/es/components/menu/style/css",
+ "element-plus/es/components/col/style/css",
+ "element-plus/es/components/icon/style/css",
+ "element-plus/es/components/row/style/css",
+ "element-plus/es/components/tag/style/css",
+ "element-plus/es/components/dialog/style/css",
+ "element-plus/es/components/loading/style/css",
+ "element-plus/es/components/radio/style/css",
+ "element-plus/es/components/radio-group/style/css",
+ "element-plus/es/components/popover/style/css",
+ "element-plus/es/components/scrollbar/style/css",
+ "element-plus/es/components/tooltip/style/css",
+ "element-plus/es/components/dropdown/style/css",
+ "element-plus/es/components/dropdown-menu/style/css",
+ "element-plus/es/components/dropdown-item/style/css",
+ "element-plus/es/components/sub-menu/style/css",
+ "element-plus/es/components/menu-item/style/css",
+ "element-plus/es/components/divider/style/css",
+ "element-plus/es/components/card/style/css",
+ "element-plus/es/components/link/style/css",
+ "element-plus/es/components/breadcrumb/style/css",
+ "element-plus/es/components/breadcrumb-item/style/css",
+ "element-plus/es/components/table/style/css",
+ "element-plus/es/components/tree-select/style/css",
+ "element-plus/es/components/table-column/style/css",
+ "element-plus/es/components/select/style/css",
+ "element-plus/es/components/option/style/css",
+ "element-plus/es/components/pagination/style/css",
+ "element-plus/es/components/tree/style/css",
+ "element-plus/es/components/alert/style/css",
+ "element-plus/es/components/radio-button/style/css",
+ "element-plus/es/components/checkbox-group/style/css",
+ "element-plus/es/components/checkbox/style/css",
+ "element-plus/es/components/tabs/style/css",
+ "element-plus/es/components/tab-pane/style/css",
+ "element-plus/es/components/rate/style/css",
+ "element-plus/es/components/date-picker/style/css",
+ "element-plus/es/components/notification/style/css",
+ "element-plus/es/components/image/style/css",
+ "element-plus/es/components/statistic/style/css",
+ "element-plus/es/components/watermark/style/css",
+ "element-plus/es/components/config-provider/style/css",
+ "element-plus/es/components/text/style/css",
+ "element-plus/es/components/drawer/style/css",
+ "element-plus/es/components/color-picker/style/css",
+ ],
+ },
+ resolve: {
+ alias: {
+ '@': fileURLToPath(new URL('./src', import.meta.url))
+ }
+ },
+ css: {
+ preprocessorOptions: {
+ scss: {
+ // 自动导入定制化样式文件进行样式覆盖
+ additionalData: `
+ @use "@/assets/css/index.scss" as *;
+ `,
+ }
+ }
+ },
+})
diff --git a/ui/yarn.lock b/ui/yarn.lock
new file mode 100644
index 0000000..396d293
--- /dev/null
+++ b/ui/yarn.lock
@@ -0,0 +1,1661 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@antfu/utils@^0.7.10":
+ version "0.7.10"
+ resolved "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d"
+ integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==
+
+"@babel/helper-string-parser@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
+ integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
+
+"@babel/helper-validator-identifier@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
+ integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
+
+"@babel/parser@^7.27.2":
+ version "7.27.2"
+ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz#577518bedb17a2ce4212afd052e01f7df0941127"
+ integrity sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==
+ dependencies:
+ "@babel/types" "^7.27.1"
+
+"@babel/runtime@^7.12.0":
+ version "7.27.1"
+ resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz#9fce313d12c9a77507f264de74626e87fd0dc541"
+ integrity sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==
+
+"@babel/types@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz#9defc53c16fc899e46941fc6901a9eea1c9d8560"
+ integrity sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==
+ dependencies:
+ "@babel/helper-string-parser" "^7.27.1"
+ "@babel/helper-validator-identifier" "^7.27.1"
+
+"@ctrl/tinycolor@^3.4.1":
+ version "3.6.1"
+ resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31"
+ integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
+
+"@element-plus/icons-vue@^2.3.1":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a"
+ integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==
+
+"@esbuild/aix-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
+ integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
+
+"@esbuild/android-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
+ integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
+
+"@esbuild/android-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
+ integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
+
+"@esbuild/android-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
+ integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
+
+"@esbuild/darwin-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
+ integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
+
+"@esbuild/darwin-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
+ integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
+
+"@esbuild/freebsd-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
+ integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
+
+"@esbuild/freebsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
+ integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
+
+"@esbuild/linux-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
+ integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
+
+"@esbuild/linux-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
+ integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
+
+"@esbuild/linux-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
+ integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
+
+"@esbuild/linux-loong64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
+ integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
+
+"@esbuild/linux-mips64el@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
+ integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
+
+"@esbuild/linux-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
+ integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
+
+"@esbuild/linux-riscv64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
+ integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
+
+"@esbuild/linux-s390x@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
+ integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
+
+"@esbuild/linux-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
+ integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
+
+"@esbuild/netbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
+ integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
+
+"@esbuild/openbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
+ integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
+
+"@esbuild/sunos-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
+ integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
+
+"@esbuild/win32-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
+ integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
+
+"@esbuild/win32-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
+ integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
+
+"@esbuild/win32-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c"
+ integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==
+
+"@floating-ui/core@^1.7.0":
+ version "1.7.0"
+ resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz#1aff27a993ea1b254a586318c29c3b16ea0f4d0a"
+ integrity sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==
+ dependencies:
+ "@floating-ui/utils" "^0.2.9"
+
+"@floating-ui/dom@^1.0.1":
+ version "1.7.0"
+ resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz#f9f83ee4fee78ac23ad9e65b128fc11a27857532"
+ integrity sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==
+ dependencies:
+ "@floating-ui/core" "^1.7.0"
+ "@floating-ui/utils" "^0.2.9"
+
+"@floating-ui/utils@^0.2.9":
+ version "0.2.9"
+ resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429"
+ integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==
+
+"@jridgewell/sourcemap-codec@^1.5.0":
+ version "1.5.0"
+ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
+ integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@parcel/watcher-android-arm64@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1"
+ integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==
+
+"@parcel/watcher-darwin-arm64@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67"
+ integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==
+
+"@parcel/watcher-darwin-x64@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8"
+ integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==
+
+"@parcel/watcher-freebsd-x64@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b"
+ integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==
+
+"@parcel/watcher-linux-arm-glibc@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1"
+ integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==
+
+"@parcel/watcher-linux-arm-musl@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e"
+ integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==
+
+"@parcel/watcher-linux-arm64-glibc@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30"
+ integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==
+
+"@parcel/watcher-linux-arm64-musl@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2"
+ integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==
+
+"@parcel/watcher-linux-x64-glibc@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e"
+ integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==
+
+"@parcel/watcher-linux-x64-musl@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee"
+ integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==
+
+"@parcel/watcher-win32-arm64@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243"
+ integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==
+
+"@parcel/watcher-win32-ia32@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6"
+ integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==
+
+"@parcel/watcher-win32-x64@2.5.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947"
+ integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==
+
+"@parcel/watcher@^2.4.1":
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200"
+ integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==
+ dependencies:
+ detect-libc "^1.0.3"
+ is-glob "^4.0.3"
+ micromatch "^4.0.5"
+ node-addon-api "^7.0.0"
+ optionalDependencies:
+ "@parcel/watcher-android-arm64" "2.5.1"
+ "@parcel/watcher-darwin-arm64" "2.5.1"
+ "@parcel/watcher-darwin-x64" "2.5.1"
+ "@parcel/watcher-freebsd-x64" "2.5.1"
+ "@parcel/watcher-linux-arm-glibc" "2.5.1"
+ "@parcel/watcher-linux-arm-musl" "2.5.1"
+ "@parcel/watcher-linux-arm64-glibc" "2.5.1"
+ "@parcel/watcher-linux-arm64-musl" "2.5.1"
+ "@parcel/watcher-linux-x64-glibc" "2.5.1"
+ "@parcel/watcher-linux-x64-musl" "2.5.1"
+ "@parcel/watcher-win32-arm64" "2.5.1"
+ "@parcel/watcher-win32-ia32" "2.5.1"
+ "@parcel/watcher-win32-x64" "2.5.1"
+
+"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7":
+ version "2.11.7"
+ resolved "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
+ integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
+
+"@rollup/pluginutils@^5.0.2", "@rollup/pluginutils@^5.1.0", "@rollup/pluginutils@^5.1.3", "@rollup/pluginutils@^5.1.4":
+ version "5.1.4"
+ resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a"
+ integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==
+ dependencies:
+ "@types/estree" "^1.0.0"
+ estree-walker "^2.0.2"
+ picomatch "^4.0.2"
+
+"@rollup/rollup-android-arm-eabi@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz#f39f09f60d4a562de727c960d7b202a2cf797424"
+ integrity sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==
+
+"@rollup/rollup-android-arm64@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz#d19af7e23760717f1d879d4ca3d2cd247742dff2"
+ integrity sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==
+
+"@rollup/rollup-darwin-arm64@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz#1c3a2fbf205d80641728e05f4a56c909e95218b7"
+ integrity sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==
+
+"@rollup/rollup-darwin-x64@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz#aa66d2ba1a25e609500e13bef06dc0e71cc0c0d4"
+ integrity sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==
+
+"@rollup/rollup-freebsd-arm64@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz#df10a7b6316a0ef1028c6ca71a081124c537e30d"
+ integrity sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==
+
+"@rollup/rollup-freebsd-x64@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz#a3fdce8a05e95b068cbcb46e4df5185e407d0c35"
+ integrity sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz#49f766c55383bd0498014a9d76924348c2f3890c"
+ integrity sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==
+
+"@rollup/rollup-linux-arm-musleabihf@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz#1d4d7d32fc557e17d52e1857817381ea365e2959"
+ integrity sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==
+
+"@rollup/rollup-linux-arm64-gnu@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz#f4fc317268441e9589edad3be8f62b6c03009bc1"
+ integrity sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==
+
+"@rollup/rollup-linux-arm64-musl@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz#63a1f1b0671cb17822dabae827fef0e443aebeb7"
+ integrity sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==
+
+"@rollup/rollup-linux-loongarch64-gnu@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz#c659b01cc6c0730b547571fc3973e1e955369f98"
+ integrity sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==
+
+"@rollup/rollup-linux-powerpc64le-gnu@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz#612e746f9ad7e58480f964d65e0d6c3f4aae69a8"
+ integrity sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==
+
+"@rollup/rollup-linux-riscv64-gnu@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz#4610dbd1dcfbbae32fbc10c20ae7387acb31110c"
+ integrity sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==
+
+"@rollup/rollup-linux-riscv64-musl@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz#054911fab40dc83fafc21e470193c058108f19d8"
+ integrity sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==
+
+"@rollup/rollup-linux-s390x-gnu@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz#98896eca8012547c7f04bd07eaa6896825f9e1a5"
+ integrity sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==
+
+"@rollup/rollup-linux-x64-gnu@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz#01cf56844a1e636ee80dfb364e72c2b7142ad896"
+ integrity sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==
+
+"@rollup/rollup-linux-x64-musl@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz#e67c7531df6dff0b4c241101d4096617fbca87c3"
+ integrity sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==
+
+"@rollup/rollup-win32-arm64-msvc@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz#7eeada98444e580674de6989284e4baacd48ea65"
+ integrity sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==
+
+"@rollup/rollup-win32-ia32-msvc@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz#516c4b54f80587b4a390aaf4940b40870271d35d"
+ integrity sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==
+
+"@rollup/rollup-win32-x64-msvc@4.41.1":
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz#848f99b0d9936d92221bb6070baeff4db6947a30"
+ integrity sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==
+
+"@transloadit/prettier-bytes@0.0.7":
+ version "0.0.7"
+ resolved "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz#cdb5399f445fdd606ed833872fa0cabdbc51686b"
+ integrity sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==
+
+"@types/estree@1.0.7", "@types/estree@^1.0.0":
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8"
+ integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
+
+"@types/event-emitter@^0.3.3":
+ version "0.3.5"
+ resolved "https://registry.npmjs.org/@types/event-emitter/-/event-emitter-0.3.5.tgz#ce9b513f72c50dcf0443a12165a93a79ba7a7092"
+ integrity sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==
+
+"@types/lodash-es@^4.17.6":
+ version "4.17.12"
+ resolved "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b"
+ integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==
+ dependencies:
+ "@types/lodash" "*"
+
+"@types/lodash@*", "@types/lodash@^4.14.182":
+ version "4.17.17"
+ resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz#fb85a04f47e9e4da888384feead0de05f7070355"
+ integrity sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==
+
+"@types/web-bluetooth@^0.0.16":
+ version "0.0.16"
+ resolved "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
+ integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
+
+"@uppy/companion-client@^2.2.2":
+ version "2.2.2"
+ resolved "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz#c70b42fdcca728ef88b3eebf7ee3e2fa04b4923b"
+ integrity sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==
+ dependencies:
+ "@uppy/utils" "^4.1.2"
+ namespace-emitter "^2.0.1"
+
+"@uppy/core@^2.1.1":
+ version "2.3.4"
+ resolved "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz#260b85b6bf3aa03cdc67da231f8c69cfbfdcc84a"
+ integrity sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==
+ dependencies:
+ "@transloadit/prettier-bytes" "0.0.7"
+ "@uppy/store-default" "^2.1.1"
+ "@uppy/utils" "^4.1.3"
+ lodash.throttle "^4.1.1"
+ mime-match "^1.0.2"
+ namespace-emitter "^2.0.1"
+ nanoid "^3.1.25"
+ preact "^10.5.13"
+
+"@uppy/store-default@^2.1.1":
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz#62a656a099bdaa012306e054d093754cb2d36e3e"
+ integrity sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==
+
+"@uppy/utils@^4.1.2", "@uppy/utils@^4.1.3":
+ version "4.1.3"
+ resolved "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz#9d0be6ece4df25f228d30ef40be0f14208258ce3"
+ integrity sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==
+ dependencies:
+ lodash.throttle "^4.1.1"
+
+"@uppy/xhr-upload@^2.0.3":
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz#0d4e355332fe0c6eb372d7731315e04d02aeeb18"
+ integrity sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==
+ dependencies:
+ "@uppy/companion-client" "^2.2.2"
+ "@uppy/utils" "^4.1.2"
+ nanoid "^3.1.25"
+
+"@vitejs/plugin-vue@^5.0.5":
+ version "5.2.4"
+ resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz#9e8a512eb174bfc2a333ba959bbf9de428d89ad8"
+ integrity sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==
+
+"@vue/compiler-core@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.15.tgz#7cbda69429490f4ec0f68126dd0d6eae050dd01c"
+ integrity sha512-nGRc6YJg/kxNqbv/7Tg4juirPnjHvuVdhcmDvQWVZXlLHjouq7VsKmV1hIxM/8yKM0VUfwT/Uzc0lO510ltZqw==
+ dependencies:
+ "@babel/parser" "^7.27.2"
+ "@vue/shared" "3.5.15"
+ entities "^4.5.0"
+ estree-walker "^2.0.2"
+ source-map-js "^1.2.1"
+
+"@vue/compiler-dom@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.15.tgz#2de7fec1a685c236585a4a1fb12cc586d7f0ffef"
+ integrity sha512-ZelQd9n+O/UCBdL00rlwCrsArSak+YLZpBVuNDio1hN3+wrCshYZEDUO3khSLAzPbF1oQS2duEoMDUHScUlYjA==
+ dependencies:
+ "@vue/compiler-core" "3.5.15"
+ "@vue/shared" "3.5.15"
+
+"@vue/compiler-sfc@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.15.tgz#d45a5c5171d8823c59725d31af406693c8816195"
+ integrity sha512-3zndKbxMsOU6afQWer75Zot/aydjtxNj0T2KLg033rAFaQUn2PGuE32ZRe4iMhflbTcAxL0yEYsRWFxtPro8RQ==
+ dependencies:
+ "@babel/parser" "^7.27.2"
+ "@vue/compiler-core" "3.5.15"
+ "@vue/compiler-dom" "3.5.15"
+ "@vue/compiler-ssr" "3.5.15"
+ "@vue/shared" "3.5.15"
+ estree-walker "^2.0.2"
+ magic-string "^0.30.17"
+ postcss "^8.5.3"
+ source-map-js "^1.2.1"
+
+"@vue/compiler-ssr@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.15.tgz#b6ffbb19ff7126fc0e60cbf9c4ca34d9a9ce9fb2"
+ integrity sha512-gShn8zRREZbrXqTtmLSCffgZXDWv8nHc/GhsW+mbwBfNZL5pI96e7IWcIq8XGQe1TLtVbu7EV9gFIVSmfyarPg==
+ dependencies:
+ "@vue/compiler-dom" "3.5.15"
+ "@vue/shared" "3.5.15"
+
+"@vue/devtools-api@^6.6.4":
+ version "6.6.4"
+ resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343"
+ integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==
+
+"@vue/reactivity@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.15.tgz#18d00ae922e8b0dc09afe952bd47510c6e4305e9"
+ integrity sha512-GaA5VUm30YWobCwpvcs9nvFKf27EdSLKDo2jA0IXzGS344oNpFNbEQ9z+Pp5ESDaxyS8FcH0vFN/XSe95BZtHQ==
+ dependencies:
+ "@vue/shared" "3.5.15"
+
+"@vue/runtime-core@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.15.tgz#0accac4b441bb4aa00f58ba353b6f61e83f45202"
+ integrity sha512-CZAlIOQ93nj0OPpWWOx4+QDLCMzBNY85IQR4Voe6vIID149yF8g9WQaWnw042f/6JfvLttK7dnyWlC1EVCRK8Q==
+ dependencies:
+ "@vue/reactivity" "3.5.15"
+ "@vue/shared" "3.5.15"
+
+"@vue/runtime-dom@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.15.tgz#048b725069f6d3fe5002e53eba118466d1fbec84"
+ integrity sha512-wFplHKzKO/v998up2iCW3RN9TNUeDMhdBcNYZgs5LOokHntrB48dyuZHspcahKZczKKh3v6i164gapMPxBTKNw==
+ dependencies:
+ "@vue/reactivity" "3.5.15"
+ "@vue/runtime-core" "3.5.15"
+ "@vue/shared" "3.5.15"
+ csstype "^3.1.3"
+
+"@vue/server-renderer@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.15.tgz#c1e8597e4bec8ea0b323c32dc032aa5c1f2983f4"
+ integrity sha512-Gehc693kVTYkLt6QSYEjGvqvdK2zZ/gf/D5zkgmvBdeB30dNnVZS8yY7+IlBmHRd1rR/zwaqeu06Ij04ZxBscg==
+ dependencies:
+ "@vue/compiler-ssr" "3.5.15"
+ "@vue/shared" "3.5.15"
+
+"@vue/shared@3.5.15":
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.5.15.tgz#4c633a0e66f38119e38eecf340b4a65b0bad7192"
+ integrity sha512-bKvgFJJL1ZX9KxMCTQY6xD9Dhe3nusd1OhyOb1cJYGqvAr0Vg8FIjHPMOEVbJ9GDT9HG+Bjdn4oS8ohKP8EvoA==
+
+"@vueuse/core@^9.1.0":
+ version "9.13.0"
+ resolved "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
+ integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==
+ dependencies:
+ "@types/web-bluetooth" "^0.0.16"
+ "@vueuse/metadata" "9.13.0"
+ "@vueuse/shared" "9.13.0"
+ vue-demi "*"
+
+"@vueuse/metadata@9.13.0":
+ version "9.13.0"
+ resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
+ integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==
+
+"@vueuse/shared@9.13.0":
+ version "9.13.0"
+ resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
+ integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==
+ dependencies:
+ vue-demi "*"
+
+"@wangeditor/basic-modules@^1.1.7":
+ version "1.1.7"
+ resolved "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz#a9c3ccf4ef53332f29550d59d3676e15f395946f"
+ integrity sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==
+ dependencies:
+ is-url "^1.2.4"
+
+"@wangeditor/code-highlight@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz#90256857714d5c0cf83ac475aea64db7bf29a7cd"
+ integrity sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==
+ dependencies:
+ prismjs "^1.23.0"
+
+"@wangeditor/core@^1.1.19":
+ version "1.1.19"
+ resolved "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz#f9155f7fd92d03cb1982405b3b82e54c31f1c2b0"
+ integrity sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==
+ dependencies:
+ "@types/event-emitter" "^0.3.3"
+ event-emitter "^0.3.5"
+ html-void-elements "^2.0.0"
+ i18next "^20.4.0"
+ scroll-into-view-if-needed "^2.2.28"
+ slate-history "^0.66.0"
+
+"@wangeditor/editor-for-vue@^5.1.12":
+ version "5.1.12"
+ resolved "https://registry.npmjs.org/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz#f7d5f239b39cdfc01d31151488de8443fe6edc64"
+ integrity sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==
+
+"@wangeditor/editor@^5.1.23":
+ version "5.1.23"
+ resolved "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.23.tgz#c9d2007b7cb0ceef6b72692b4ee87b01ee2367b3"
+ integrity sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==
+ dependencies:
+ "@uppy/core" "^2.1.1"
+ "@uppy/xhr-upload" "^2.0.3"
+ "@wangeditor/basic-modules" "^1.1.7"
+ "@wangeditor/code-highlight" "^1.0.3"
+ "@wangeditor/core" "^1.1.19"
+ "@wangeditor/list-module" "^1.0.5"
+ "@wangeditor/table-module" "^1.1.4"
+ "@wangeditor/upload-image-module" "^1.0.2"
+ "@wangeditor/video-module" "^1.1.4"
+ dom7 "^3.0.0"
+ is-hotkey "^0.2.0"
+ lodash.camelcase "^4.3.0"
+ lodash.clonedeep "^4.5.0"
+ lodash.debounce "^4.0.8"
+ lodash.foreach "^4.5.0"
+ lodash.isequal "^4.5.0"
+ lodash.throttle "^4.1.1"
+ lodash.toarray "^4.4.0"
+ nanoid "^3.2.0"
+ slate "^0.72.0"
+ snabbdom "^3.1.0"
+
+"@wangeditor/list-module@^1.0.5":
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.5.tgz#3fc0b167acddf885536b45fa0c127f9c6adaea33"
+ integrity sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==
+
+"@wangeditor/table-module@^1.1.4":
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.4.tgz#757d4a5868b2b658041cd323854a4d707c8347e9"
+ integrity sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==
+
+"@wangeditor/upload-image-module@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz#89e9b9467e10cbc6b11dc5748e08dd23aaebee30"
+ integrity sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==
+
+"@wangeditor/video-module@^1.1.4":
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.4.tgz#b9df1b3ab2cd53f678b19b4d927e200774a6f532"
+ integrity sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==
+
+acorn@^8.14.0:
+ version "8.14.1"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb"
+ integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==
+
+anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+async-validator@^4.2.5:
+ version "4.2.5"
+ resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
+ integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+axios@^1.7.2:
+ version "1.9.0"
+ resolved "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz#25534e3b72b54540077d33046f77e3b8d7081901"
+ integrity sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==
+ dependencies:
+ follow-redirects "^1.15.6"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
+ integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
+
+brace-expansion@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^3.0.3, braces@~3.0.2:
+ version "3.0.3"
+ resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
+ dependencies:
+ fill-range "^7.1.1"
+
+call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
+ integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
+ dependencies:
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+
+chokidar@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
+ integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+chokidar@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30"
+ integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==
+ dependencies:
+ readdirp "^4.0.1"
+
+combined-stream@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+compute-scroll-into-view@^1.0.20:
+ version "1.0.20"
+ resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
+ integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
+
+confbox@^0.1.8:
+ version "0.1.8"
+ resolved "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06"
+ integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==
+
+confbox@^0.2.1:
+ version "0.2.2"
+ resolved "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110"
+ integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==
+
+csstype@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+ integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+d@1, d@^1.0.1, d@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de"
+ integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==
+ dependencies:
+ es5-ext "^0.10.64"
+ type "^2.7.2"
+
+dayjs@^1.11.13:
+ version "1.11.13"
+ resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
+ integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
+
+debug@^4.3.7:
+ version "4.4.1"
+ resolved "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
+ integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
+ dependencies:
+ ms "^2.1.3"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+detect-libc@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+ integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
+
+dom7@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz#b861ce5d67a6becd7aaa3ad02942ff14b1240331"
+ integrity sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==
+ dependencies:
+ ssr-window "^3.0.0-alpha.1"
+
+dunder-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
+ integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
+ dependencies:
+ call-bind-apply-helpers "^1.0.1"
+ es-errors "^1.3.0"
+ gopd "^1.2.0"
+
+element-plus@^2.7.6:
+ version "2.9.11"
+ resolved "https://registry.npmjs.org/element-plus/-/element-plus-2.9.11.tgz#c939a8d945330f596b7a35aae0e501ea170874a2"
+ integrity sha512-x4L/6YC8de4JtuE3vpaEugJdQIeHQaHtIYKyk67IeF6dTIiVax45aX4nWOygnh+xX+0gTvL6xO+9BZhPA3G82w==
+ dependencies:
+ "@ctrl/tinycolor" "^3.4.1"
+ "@element-plus/icons-vue" "^2.3.1"
+ "@floating-ui/dom" "^1.0.1"
+ "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7"
+ "@types/lodash" "^4.14.182"
+ "@types/lodash-es" "^4.17.6"
+ "@vueuse/core" "^9.1.0"
+ async-validator "^4.2.5"
+ dayjs "^1.11.13"
+ escape-html "^1.0.3"
+ lodash "^4.17.21"
+ lodash-es "^4.17.21"
+ lodash-unified "^1.0.2"
+ memoize-one "^6.0.0"
+ normalize-wheel-es "^1.2.0"
+
+entities@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
+es-define-property@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
+ integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+es-module-lexer@^1.3.0:
+ version "1.7.0"
+ resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a"
+ integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==
+
+es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
+ integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
+ dependencies:
+ es-errors "^1.3.0"
+
+es-set-tostringtag@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
+ integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
+ dependencies:
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
+ has-tostringtag "^1.0.2"
+ hasown "^2.0.2"
+
+es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14:
+ version "0.10.64"
+ resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714"
+ integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==
+ dependencies:
+ es6-iterator "^2.0.3"
+ es6-symbol "^3.1.3"
+ esniff "^2.0.1"
+ next-tick "^1.1.0"
+
+es6-iterator@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+ integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==
+ dependencies:
+ d "1"
+ es5-ext "^0.10.35"
+ es6-symbol "^3.1.1"
+
+es6-symbol@^3.1.1, es6-symbol@^3.1.3:
+ version "3.1.4"
+ resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c"
+ integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==
+ dependencies:
+ d "^1.0.2"
+ ext "^1.7.0"
+
+esbuild@^0.21.3:
+ version "0.21.5"
+ resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
+ integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==
+ optionalDependencies:
+ "@esbuild/aix-ppc64" "0.21.5"
+ "@esbuild/android-arm" "0.21.5"
+ "@esbuild/android-arm64" "0.21.5"
+ "@esbuild/android-x64" "0.21.5"
+ "@esbuild/darwin-arm64" "0.21.5"
+ "@esbuild/darwin-x64" "0.21.5"
+ "@esbuild/freebsd-arm64" "0.21.5"
+ "@esbuild/freebsd-x64" "0.21.5"
+ "@esbuild/linux-arm" "0.21.5"
+ "@esbuild/linux-arm64" "0.21.5"
+ "@esbuild/linux-ia32" "0.21.5"
+ "@esbuild/linux-loong64" "0.21.5"
+ "@esbuild/linux-mips64el" "0.21.5"
+ "@esbuild/linux-ppc64" "0.21.5"
+ "@esbuild/linux-riscv64" "0.21.5"
+ "@esbuild/linux-s390x" "0.21.5"
+ "@esbuild/linux-x64" "0.21.5"
+ "@esbuild/netbsd-x64" "0.21.5"
+ "@esbuild/openbsd-x64" "0.21.5"
+ "@esbuild/sunos-x64" "0.21.5"
+ "@esbuild/win32-arm64" "0.21.5"
+ "@esbuild/win32-ia32" "0.21.5"
+ "@esbuild/win32-x64" "0.21.5"
+
+escape-html@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+escape-string-regexp@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
+ integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
+
+esniff@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
+ integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
+ dependencies:
+ d "^1.0.1"
+ es5-ext "^0.10.62"
+ event-emitter "^0.3.5"
+ type "^2.7.2"
+
+estree-walker@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+ integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
+estree-walker@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d"
+ integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==
+ dependencies:
+ "@types/estree" "^1.0.0"
+
+event-emitter@^0.3.5:
+ version "0.3.5"
+ resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
+ integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+
+exsolve@^1.0.1:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/exsolve/-/exsolve-1.0.5.tgz#1f5b6b4fe82ad6b28a173ccb955a635d77859dcf"
+ integrity sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==
+
+ext@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f"
+ integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==
+ dependencies:
+ type "^2.7.2"
+
+fast-glob@^3.3.2, fast-glob@^3.3.3:
+ version "3.3.3"
+ resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
+ integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.8"
+
+fastq@^1.6.0:
+ version "1.19.1"
+ resolved "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5"
+ integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==
+ dependencies:
+ reusify "^1.0.4"
+
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+follow-redirects@^1.15.6:
+ version "1.15.9"
+ resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
+ integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
+
+form-data@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c"
+ integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ es-set-tostringtag "^2.1.0"
+ mime-types "^2.1.12"
+
+fsevents@~2.3.2, fsevents@~2.3.3:
+ version "2.3.3"
+ resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+get-intrinsic@^1.2.6:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
+ integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
+ dependencies:
+ call-bind-apply-helpers "^1.0.2"
+ es-define-property "^1.0.1"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.1.1"
+ function-bind "^1.1.2"
+ get-proto "^1.0.1"
+ gopd "^1.2.0"
+ has-symbols "^1.1.0"
+ hasown "^2.0.2"
+ math-intrinsics "^1.1.0"
+
+get-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
+ integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
+ dependencies:
+ dunder-proto "^1.0.1"
+ es-object-atoms "^1.0.0"
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+gopd@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
+ integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
+
+has-symbols@^1.0.3, has-symbols@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
+ integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
+
+has-tostringtag@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
+ integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
+ dependencies:
+ has-symbols "^1.0.3"
+
+hasown@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+ dependencies:
+ function-bind "^1.1.2"
+
+html-void-elements@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f"
+ integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
+
+i18next@^20.4.0:
+ version "20.6.1"
+ resolved "https://registry.npmjs.org/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345"
+ integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==
+ dependencies:
+ "@babel/runtime" "^7.12.0"
+
+immer@^9.0.6:
+ version "9.0.21"
+ resolved "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
+ integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
+
+immutable@^5.0.2:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/immutable/-/immutable-5.1.2.tgz#e8169476414505e5a4fa650107b65e1227d16d4b"
+ integrity sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ==
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-hotkey@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz#1835a68171a91e5c9460869d96336947c8340cef"
+ integrity sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-plain-object@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
+
+is-url@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
+ integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
+
+js-tokens@^9.0.1:
+ version "9.0.1"
+ resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4"
+ integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==
+
+local-pkg@^0.5.0, local-pkg@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d"
+ integrity sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==
+ dependencies:
+ mlly "^1.7.3"
+ pkg-types "^1.2.1"
+
+local-pkg@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz#f5fe74a97a3bd3c165788ee08ca9fbe998dc58dd"
+ integrity sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==
+ dependencies:
+ mlly "^1.7.4"
+ pkg-types "^2.0.1"
+ quansync "^0.2.8"
+
+lodash-es@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+ integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
+lodash-unified@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894"
+ integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==
+
+lodash.camelcase@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+ integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
+lodash.clonedeep@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
+ integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
+
+lodash.debounce@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+ integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
+
+lodash.foreach@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
+ integrity sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==
+
+lodash.isequal@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+ integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
+lodash.throttle@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
+ integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==
+
+lodash.toarray@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
+ integrity sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==
+
+lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+magic-string@^0.30.1, magic-string@^0.30.10, magic-string@^0.30.14, magic-string@^0.30.17:
+ version "0.30.17"
+ resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453"
+ integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.5.0"
+
+math-intrinsics@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
+ integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
+
+memoize-one@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
+ integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
+
+merge2@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.5, micromatch@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
+ integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
+ dependencies:
+ braces "^3.0.3"
+ picomatch "^2.3.1"
+
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-match@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz#3f87c31e9af1a5fd485fb9db134428b23bbb7ba8"
+ integrity sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==
+ dependencies:
+ wildcard "^1.1.0"
+
+mime-types@^2.1.12:
+ version "2.1.35"
+ resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+minimatch@^9.0.4, minimatch@^9.0.5:
+ version "9.0.5"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
+ integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+mlly@^1.7.3, mlly@^1.7.4:
+ version "1.7.4"
+ resolved "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f"
+ integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==
+ dependencies:
+ acorn "^8.14.0"
+ pathe "^2.0.1"
+ pkg-types "^1.3.0"
+ ufo "^1.5.4"
+
+ms@^2.1.3:
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+namespace-emitter@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz#978d51361c61313b4e6b8cf6f3853d08dfa2b17c"
+ integrity sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==
+
+nanoid@^3.1.25, nanoid@^3.2.0, nanoid@^3.3.8:
+ version "3.3.11"
+ resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
+ integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
+
+next-tick@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
+ integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
+
+node-addon-api@^7.0.0:
+ version "7.1.1"
+ resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
+ integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-wheel-es@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e"
+ integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==
+
+pathe@^2.0.1, pathe@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716"
+ integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==
+
+picocolors@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
+ integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+picomatch@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
+ integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
+
+pkg-types@^1.2.1, pkg-types@^1.3.0:
+ version "1.3.1"
+ resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df"
+ integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==
+ dependencies:
+ confbox "^0.1.8"
+ mlly "^1.7.4"
+ pathe "^2.0.1"
+
+pkg-types@^2.0.1:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz#70c9e1b9c74b63fdde749876ee0aa007ea9edead"
+ integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==
+ dependencies:
+ confbox "^0.2.1"
+ exsolve "^1.0.1"
+ pathe "^2.0.3"
+
+postcss@^8.4.43, postcss@^8.5.3:
+ version "8.5.3"
+ resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb"
+ integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==
+ dependencies:
+ nanoid "^3.3.8"
+ picocolors "^1.1.1"
+ source-map-js "^1.2.1"
+
+preact@^10.5.13:
+ version "10.26.7"
+ resolved "https://registry.npmjs.org/preact/-/preact-10.26.7.tgz#7b4b2620dfbbd9d4654d88f1b3cee0fb9dea6e80"
+ integrity sha512-43xS+QYc1X1IPbw03faSgY6I6OYWcLrJRv3hU0+qMOfh/XCHcP0MX2CVjNARYR2cC/guu975sta4OcjlczxD7g==
+
+prismjs@^1.23.0:
+ version "1.30.0"
+ resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9"
+ integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==
+
+proxy-from-env@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+ integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
+quansync@^0.2.8:
+ version "0.2.10"
+ resolved "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz#32053cf166fa36511aae95fc49796116f2dc20e1"
+ integrity sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+readdirp@^4.0.1:
+ version "4.1.2"
+ resolved "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d"
+ integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+reusify@^1.0.4:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f"
+ integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==
+
+rollup@^4.20.0:
+ version "4.41.1"
+ resolved "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz#46ddc1b33cf1b0baa99320d3b0b4973dc2253b6a"
+ integrity sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==
+ dependencies:
+ "@types/estree" "1.0.7"
+ optionalDependencies:
+ "@rollup/rollup-android-arm-eabi" "4.41.1"
+ "@rollup/rollup-android-arm64" "4.41.1"
+ "@rollup/rollup-darwin-arm64" "4.41.1"
+ "@rollup/rollup-darwin-x64" "4.41.1"
+ "@rollup/rollup-freebsd-arm64" "4.41.1"
+ "@rollup/rollup-freebsd-x64" "4.41.1"
+ "@rollup/rollup-linux-arm-gnueabihf" "4.41.1"
+ "@rollup/rollup-linux-arm-musleabihf" "4.41.1"
+ "@rollup/rollup-linux-arm64-gnu" "4.41.1"
+ "@rollup/rollup-linux-arm64-musl" "4.41.1"
+ "@rollup/rollup-linux-loongarch64-gnu" "4.41.1"
+ "@rollup/rollup-linux-powerpc64le-gnu" "4.41.1"
+ "@rollup/rollup-linux-riscv64-gnu" "4.41.1"
+ "@rollup/rollup-linux-riscv64-musl" "4.41.1"
+ "@rollup/rollup-linux-s390x-gnu" "4.41.1"
+ "@rollup/rollup-linux-x64-gnu" "4.41.1"
+ "@rollup/rollup-linux-x64-musl" "4.41.1"
+ "@rollup/rollup-win32-arm64-msvc" "4.41.1"
+ "@rollup/rollup-win32-ia32-msvc" "4.41.1"
+ "@rollup/rollup-win32-x64-msvc" "4.41.1"
+ fsevents "~2.3.2"
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+sass@^1.89.0:
+ version "1.89.0"
+ resolved "https://registry.npmjs.org/sass/-/sass-1.89.0.tgz#6df72360c5c3ec2a9833c49adafe57b28206752d"
+ integrity sha512-ld+kQU8YTdGNjOLfRWBzewJpU5cwEv/h5yyqlSeJcj6Yh8U4TDA9UA5FPicqDz/xgRPWRSYIQNiFks21TbA9KQ==
+ dependencies:
+ chokidar "^4.0.0"
+ immutable "^5.0.2"
+ source-map-js ">=0.6.2 <2.0.0"
+ optionalDependencies:
+ "@parcel/watcher" "^2.4.1"
+
+scroll-into-view-if-needed@^2.2.28:
+ version "2.2.31"
+ resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
+ integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
+ dependencies:
+ compute-scroll-into-view "^1.0.20"
+
+scule@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz#6efbd22fd0bb801bdcc585c89266a7d2daa8fbd3"
+ integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==
+
+slate-history@^0.66.0:
+ version "0.66.0"
+ resolved "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz#ac63fddb903098ceb4c944433e3f75fe63acf940"
+ integrity sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==
+ dependencies:
+ is-plain-object "^5.0.0"
+
+slate@^0.72.0:
+ version "0.72.8"
+ resolved "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz#5a018edf24e45448655293a68bfbcf563aa5ba81"
+ integrity sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==
+ dependencies:
+ immer "^9.0.6"
+ is-plain-object "^5.0.0"
+ tiny-warning "^1.0.3"
+
+snabbdom@^3.1.0:
+ version "3.6.2"
+ resolved "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.2.tgz#57dd66878f6320497fa7f67941df356a045c75a1"
+ integrity sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==
+
+"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
+ integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
+
+ssr-window@^3.0.0-alpha.1:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz#fd5b82801638943e0cc704c4691801435af7ac37"
+ integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==
+
+strip-literal@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz#26906e65f606d49f748454a08084e94190c2e5ad"
+ integrity sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==
+ dependencies:
+ js-tokens "^9.0.1"
+
+tiny-warning@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+ integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+type@^2.7.2:
+ version "2.7.3"
+ resolved "https://registry.npmjs.org/type/-/type-2.7.3.tgz#436981652129285cc3ba94f392886c2637ea0486"
+ integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==
+
+ufo@^1.5.4:
+ version "1.6.1"
+ resolved "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b"
+ integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==
+
+unimport@^3.7.2:
+ version "3.14.6"
+ resolved "https://registry.npmjs.org/unimport/-/unimport-3.14.6.tgz#f01170aa2fb94c4f97b22c0ac2822ef7e8e0726d"
+ integrity sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==
+ dependencies:
+ "@rollup/pluginutils" "^5.1.4"
+ acorn "^8.14.0"
+ escape-string-regexp "^5.0.0"
+ estree-walker "^3.0.3"
+ fast-glob "^3.3.3"
+ local-pkg "^1.0.0"
+ magic-string "^0.30.17"
+ mlly "^1.7.4"
+ pathe "^2.0.1"
+ picomatch "^4.0.2"
+ pkg-types "^1.3.0"
+ scule "^1.3.0"
+ strip-literal "^2.1.1"
+ unplugin "^1.16.1"
+
+unplugin-auto-import@^0.17.6:
+ version "0.17.8"
+ resolved "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.8.tgz#8dd5d1f21700171242553f1a476bd43ffad74af6"
+ integrity sha512-CHryj6HzJ+n4ASjzwHruD8arhbdl+UXvhuAIlHDs15Y/IMecG3wrf7FVg4pVH/DIysbq/n0phIjNHAjl7TG7Iw==
+ dependencies:
+ "@antfu/utils" "^0.7.10"
+ "@rollup/pluginutils" "^5.1.0"
+ fast-glob "^3.3.2"
+ local-pkg "^0.5.0"
+ magic-string "^0.30.10"
+ minimatch "^9.0.4"
+ unimport "^3.7.2"
+ unplugin "^1.11.0"
+
+unplugin-element-plus@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.npmjs.org/unplugin-element-plus/-/unplugin-element-plus-0.8.0.tgz#320c8b43a87fe6d680b9117656476f597bccf700"
+ integrity sha512-jByUGY3FG2B8RJKFryqxx4eNtSTj+Hjlo8edcOdJymewndDQjThZ1pRUQHRjQsbKhTV2jEctJV7t7RJ405UL4g==
+ dependencies:
+ "@rollup/pluginutils" "^5.0.2"
+ es-module-lexer "^1.3.0"
+ magic-string "^0.30.1"
+ unplugin "^1.3.2"
+
+unplugin-vue-components@^0.27.2:
+ version "0.27.5"
+ resolved "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.5.tgz#81b8460c5183146c084c09fae5ec9db7afd45c4b"
+ integrity sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg==
+ dependencies:
+ "@antfu/utils" "^0.7.10"
+ "@rollup/pluginutils" "^5.1.3"
+ chokidar "^3.6.0"
+ debug "^4.3.7"
+ fast-glob "^3.3.2"
+ local-pkg "^0.5.1"
+ magic-string "^0.30.14"
+ minimatch "^9.0.5"
+ mlly "^1.7.3"
+ unplugin "^1.16.0"
+
+unplugin@^1.11.0, unplugin@^1.16.0, unplugin@^1.16.1, unplugin@^1.3.2:
+ version "1.16.1"
+ resolved "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz#a844d2e3c3b14a4ac2945c42be80409321b61199"
+ integrity sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==
+ dependencies:
+ acorn "^8.14.0"
+ webpack-virtual-modules "^0.6.2"
+
+vite@^5.3.1:
+ version "5.4.19"
+ resolved "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz#20efd060410044b3ed555049418a5e7d1998f959"
+ integrity sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==
+ dependencies:
+ esbuild "^0.21.3"
+ postcss "^8.4.43"
+ rollup "^4.20.0"
+ optionalDependencies:
+ fsevents "~2.3.3"
+
+vue-demi@*:
+ version "0.14.10"
+ resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
+ integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
+
+vue-router@^4.3.3:
+ version "4.5.1"
+ resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz#47bffe2d3a5479d2886a9a244547a853aa0abf69"
+ integrity sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==
+ dependencies:
+ "@vue/devtools-api" "^6.6.4"
+
+vue@^3.4.29:
+ version "3.5.15"
+ resolved "https://registry.npmjs.org/vue/-/vue-3.5.15.tgz#5896569a33a1bcafd764c6b27e4e6f8cb55f4bee"
+ integrity sha512-aD9zK4rB43JAMK/5BmS4LdPiEp8Fdh8P1Ve/XNuMF5YRf78fCyPE6FUbQwcaWQ5oZ1R2CD9NKE0FFOVpMR7gEQ==
+ dependencies:
+ "@vue/compiler-dom" "3.5.15"
+ "@vue/compiler-sfc" "3.5.15"
+ "@vue/runtime-dom" "3.5.15"
+ "@vue/server-renderer" "3.5.15"
+ "@vue/shared" "3.5.15"
+
+webpack-virtual-modules@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8"
+ integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==
+
+wildcard@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz#a7020453084d8cd2efe70ba9d3696263de1710a5"
+ integrity sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==