Compare commits
371 Commits
Author | SHA1 | Date | |
---|---|---|---|
c6a47d0e69 | |||
25ee3c9bb0 | |||
ba2a295f09 | |||
f1dacb165a | |||
40f7e34528 | |||
1757a8fd4f | |||
3a947518ef | |||
f318e23220 | |||
45b2507948 | |||
b4b8c38294 | |||
597dfccf84 | |||
|
04ff77ed3e | ||
|
fd2ac75c44 | ||
|
b6a9a1d435 | ||
|
13ddda300e | ||
|
1cf243e542 | ||
|
ece6e571f3 | ||
|
98f4d75d59 | ||
|
9403199719 | ||
|
db012a8f51 | ||
|
583beb6448 | ||
|
eab090c2a7 | ||
|
839af4f589 | ||
|
6f3054a030 | ||
|
9ee89c5287 | ||
|
d9b98386d2 | ||
|
10d177d61d | ||
|
89e883ff2c | ||
|
2853357b8f | ||
|
fd614d9f21 | ||
|
5ef8bb1d9a | ||
|
bd36a8f321 | ||
|
01899d7e14 | ||
|
d08d8f2cda | ||
|
9ebef8ec92 | ||
|
02e5a206bf | ||
|
5217896e3d | ||
|
b6a9f488cb | ||
|
ec50d66c65 | ||
|
3738c5b744 | ||
|
ddf742e4d9 | ||
|
9518070c08 | ||
|
aac89f3df7 | ||
|
9a629b7ea3 | ||
|
2d1860f052 | ||
|
918c4c1de8 | ||
|
0c4fd32a77 | ||
|
acf3a907b4 | ||
|
038c6e4637 | ||
|
e9b3520023 | ||
|
70ecf0aed8 | ||
|
d89dc8b2d8 | ||
|
cb9c5ffcc5 | ||
|
d2c976323e | ||
|
1dee271b14 | ||
|
faeee8cdce | ||
|
be2b51ad1e | ||
|
7fe265c45d | ||
|
5f31d444d4 | ||
|
a2f6cc7c79 | ||
|
7b549f3079 | ||
|
626ba788c7 | ||
|
edcf038602 | ||
|
45ef20468b | ||
|
e934fdc2d5 | ||
|
e8159a17e1 | ||
|
4614ee3f53 | ||
|
bb85feb549 | ||
|
5398f551ba | ||
|
f2d0192277 | ||
|
b809fe7b69 | ||
|
e97a614832 | ||
|
595a71792c | ||
|
3be08dfa92 | ||
|
42237dfe11 | ||
|
7fc051fdb0 | ||
|
81adf94725 | ||
|
24d82e4772 | ||
|
64a49ad0ee | ||
|
4ee3c69a4a | ||
|
af0c1b82b1 | ||
|
6fbf2cc6c0 | ||
|
861d5d849b | ||
|
b650bae481 | ||
|
ca12f4a83e | ||
|
b8bfbbe71d | ||
|
33372e5c1e | ||
|
03192bf0fd | ||
|
193ccc9712 | ||
|
85860fb80a | ||
|
1c2ee04d8c | ||
|
7c4ee0a1e8 | ||
|
13f2f54e2a | ||
|
ba63ef6d15 | ||
|
79fe372f80 | ||
|
5e0b942d3f | ||
|
80cba65fc3 | ||
|
fc066ade71 | ||
|
c29e36ca1f | ||
|
71359d813c | ||
|
4153660620 | ||
|
e484e2142a | ||
|
3b38399d32 | ||
|
10b01a2e23 | ||
|
01eafa8efc | ||
|
eddbccaf23 | ||
|
4290a53654 | ||
|
eb00e2b31e | ||
|
4830dad754 | ||
|
ecbe67e666 | ||
|
4916845156 | ||
|
826351981c | ||
|
e2382b3cec | ||
|
8b608641b0 | ||
|
fa1810ebd7 | ||
|
9d46e6eb2b | ||
|
761eb1853f | ||
|
61adcc0b32 | ||
|
cf0b0dc077 | ||
|
d856c7c821 | ||
|
85b275c143 | ||
|
a0eec79b25 | ||
|
0d038bd0fe | ||
|
7010aa5658 | ||
|
4b9ea7a1de | ||
|
568367d2e7 | ||
|
34f7f2bd62 | ||
|
9e337a6692 | ||
|
2170658930 | ||
|
da2451257f | ||
|
7ca9c45855 | ||
|
a1cac655ce | ||
|
e4af04df97 | ||
|
7ff9a9fe50 | ||
|
01f9ff0f80 | ||
|
576c47a90d | ||
|
a5ba2d2ad9 | ||
|
bb2f60d22b | ||
|
7e62b47795 | ||
|
9821987e2d | ||
|
c6f6ed0cd6 | ||
|
6252f2154c | ||
|
487e184a9c | ||
|
636963cfd1 | ||
|
ea53348511 | ||
|
3399a4ff11 | ||
|
9241c4cae5 | ||
|
4de5327e87 | ||
|
1a3ecaf9e0 | ||
|
9dd5329ef0 | ||
|
e3b5a4463f | ||
|
75ffa05d65 | ||
|
47488d6bf5 | ||
|
44ac257c3b | ||
|
2543014ae2 | ||
|
cd8f97aab3 | ||
|
ac7702ad20 | ||
|
a5a6b40b5e | ||
|
24e59e302a | ||
|
1220f02793 | ||
|
d635029b00 | ||
|
a4633b809c | ||
|
f9f2d5b956 | ||
|
0195b0259c | ||
|
09bd9583c2 | ||
|
7f96ccca8b | ||
|
cf41c0e75f | ||
|
4200a7c5de | ||
|
307523b3be | ||
|
e3fd87ce21 | ||
|
6ab33b7c64 | ||
|
25371bad43 | ||
|
8be8ca7cb4 | ||
|
20f6db1dc6 | ||
|
fa0eb26d9a | ||
|
299cdd1770 | ||
|
9326ca716b | ||
|
6d2ab99fa3 | ||
|
898159ab3a | ||
|
2ecbee9561 | ||
|
8ad34b997e | ||
|
004a3f5668 | ||
|
095ba9f694 | ||
|
8f227774ea | ||
|
b9efae5595 | ||
|
951f44a105 | ||
|
ce22c048de | ||
|
4b87315419 | ||
|
f78f7bf5f4 | ||
|
21ee444e3f | ||
|
57c275e242 | ||
|
e4b01330ae | ||
|
65d0169aa7 | ||
|
60882a1d47 | ||
|
78435af514 | ||
|
9b30d479fd | ||
|
5b1e48e301 | ||
|
27fe05a636 | ||
|
689da6d2ac | ||
|
d3e39b3d6c | ||
|
8d5c1a616f | ||
|
6b4fc9ed42 | ||
|
1f03b484d1 | ||
|
5b54371cfc | ||
|
aae5223ad2 | ||
|
233061fae4 | ||
|
121b0b4dac | ||
|
aad4a4ac13 | ||
|
fc3fc344a4 | ||
|
5195975a37 | ||
|
87824ad22f | ||
|
250974ca58 | ||
|
6b22ad9eee | ||
|
a4977f80b3 | ||
|
868ec844d1 | ||
|
cc72c55751 | ||
|
f0c861c796 | ||
|
0108fdb36b | ||
|
d9c8047cf8 | ||
|
7e7f313aed | ||
|
4ead559ae2 | ||
|
97fec2b58b | ||
|
da10e9d1a8 | ||
|
6577201387 | ||
|
4f4ee30cff | ||
|
513bf28f67 | ||
|
a28e6dcd25 | ||
|
fc58997116 | ||
|
eb470320fa | ||
|
4b4350b1b9 | ||
|
2cfa14bc51 | ||
|
4f4cb35490 | ||
|
6db2b55225 | ||
|
c0e918ab0e | ||
|
e9903beecc | ||
|
52c1832f99 | ||
|
f8723cc8ff | ||
|
6cdf1403e8 | ||
|
2a6c057ec1 | ||
|
335ab745ca | ||
|
cebd237b98 | ||
|
dcbdfdbbce | ||
|
714e59b605 | ||
|
d096dc656f | ||
|
1a17d36cce | ||
|
c739f2fbed | ||
|
9bb4a3dae7 | ||
|
96dac789eb | ||
|
6a0c620f6e | ||
|
947c15f404 | ||
|
071919defd | ||
|
cd575ebc3f | ||
|
beafc51393 | ||
|
6da3ef4c5b | ||
|
95f40b903f | ||
|
3e706b361a | ||
|
c8c47607f4 | ||
|
cbe91187e6 | ||
|
8e79a71b1f | ||
|
75eea70d6f | ||
|
9cb23a94a7 | ||
|
ed8ada2ecc | ||
|
6794b1135c | ||
|
05922d6484 | ||
|
09f6a81797 | ||
|
30cf0c06fc | ||
|
c68fc57e55 | ||
|
b6bcff27c0 | ||
|
01d27afdde | ||
|
072a27c5b3 | ||
|
c885a0e60b | ||
|
a29aaed59c | ||
|
dd9590ea84 | ||
|
efccda92ea | ||
|
3d25cba611 | ||
|
ffd4f03f04 | ||
|
b27f525152 | ||
|
d8c583b5a6 | ||
|
895f6c81c8 | ||
|
4661a5aa5c | ||
|
53512232be | ||
|
04a5cba4f1 | ||
|
16f476e84f | ||
|
7de7784428 | ||
|
05fb737bf4 | ||
|
d812d2a928 | ||
|
edeeeb06c1 | ||
|
89e408ce90 | ||
|
1d9d9d057d | ||
|
489faeda9a | ||
|
039a824302 | ||
|
fed4d3aa84 | ||
|
c1a915d8c5 | ||
|
475c822992 | ||
|
4d1d45f85f | ||
|
129b5bea16 | ||
|
9f32af9dfe | ||
|
799f12bbf1 | ||
|
b587430e3b | ||
|
e81dc80a57 | ||
|
945af9de76 | ||
|
c15c981254 | ||
|
879f0ab05e | ||
|
ec2b7d1a0a | ||
|
40ecab5a08 | ||
|
5f726d9dc6 | ||
|
945fe04b15 | ||
|
db79588ca5 | ||
|
c181e74ae5 | ||
|
50a41fb154 | ||
|
30a85560ab | ||
|
18b5b2ccf7 | ||
|
5b79ff5cd3 | ||
|
e714443e8d | ||
|
0cb5f1c107 | ||
|
36e885ffde | ||
|
e9ceca7f2d | ||
|
6fb0f49cb0 | ||
|
96dd9d77f9 | ||
|
ddf41b5307 | ||
|
9fb56f7b08 | ||
|
6cc0613668 | ||
|
6fab2ea2cd | ||
|
dd1a47344a | ||
|
5a99fe23d8 | ||
|
2a6b3bd909 | ||
|
e8272a723e | ||
|
2fc25ad943 | ||
|
25bf2959f0 | ||
|
f1dc6e77af | ||
|
e53c08839f | ||
|
adb674d5ed | ||
|
1bcd1e25d0 | ||
|
4ee37785c2 | ||
|
15ce5c73cd | ||
|
423ca88806 | ||
|
a8df81aad4 | ||
|
29154803b0 | ||
|
7101bad7fe | ||
|
7fb56a99ae | ||
|
c6fc18483d | ||
|
d0c8525cbf | ||
|
e0109cc05e | ||
|
1bfea8deb8 | ||
|
92bc3e8d6a | ||
|
10fe1918d2 | ||
|
db304e38b3 | ||
|
3ade19fcdc | ||
|
d3f95c4d46 | ||
|
ad30c8bf3c | ||
|
0260e6c3cb | ||
|
fdc3ad80b0 | ||
|
0f37f31c43 | ||
|
e7785d992d | ||
|
4d2b89e112 | ||
|
7a296b6a08 | ||
|
fd74fa76a9 | ||
|
a78927471d | ||
|
79a4c4df05 | ||
|
83297d9cfc | ||
|
de874519d3 | ||
|
b6eddc1dbe | ||
|
3e5fada769 | ||
|
94f625f47b | ||
|
8f4f2c78e8 | ||
|
6b62071d05 | ||
|
caa5f773d8 | ||
|
667db6bac8 | ||
|
6f79d3b2e8 | ||
|
6462e586c8 | ||
|
3b069128c6 |
6
.gitattributes
vendored
@ -1,2 +1,4 @@
|
||||
*.js linguist-language=java
|
||||
*.css linguist-language=java
|
||||
*.js linguist-language=javascript
|
||||
*.css linguist-language=css
|
||||
*.java linguist-language=java
|
||||
*.vue linguist-language=vue
|
4
.gitignore
vendored
@ -11,7 +11,7 @@ target/
|
||||
.project
|
||||
.classpath
|
||||
|
||||
# idea ignore
|
||||
# idea ignore
|
||||
.idea/
|
||||
*.ipr
|
||||
*.iml
|
||||
@ -26,7 +26,7 @@ logs/
|
||||
*.patch
|
||||
*.tmp
|
||||
|
||||
# system ignore
|
||||
# system ignore
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
|
2
LICENSE
@ -1,5 +1,5 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
|
114
README.md
@ -1,43 +1,62 @@
|
||||
# 学之思在线考试系统
|
||||
<p></p>
|
||||
<p></p>
|
||||
|
||||
### 项目介绍
|
||||
学之思在线考试系统是一款 java + vue 的前后端分离的考试系统。主要优点是开发、部署简单快捷、界面设计友好、代码结构清晰。目前支持web端和微信小程序,能覆盖到pc机和手机等设备。
|
||||
<p align="center">
|
||||
<a href="https://www.mindskip.net" target="_blank">
|
||||
<img src="doc/image/logo/1.png" height="80"/>
|
||||
<a/>
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://gitee.com/mindskip/xzs-mysql)
|
||||
[](https://gitee.com/mindskip/xzs-mysql)
|
||||
[](https://github.com/mindskip/xzs-mysql)
|
||||
[](https://github.com/mindskip/xzs-mysql)
|
||||
[](https://gitee.com/mindskip/xzs-mysql/blob/master/LICENSE)
|
||||
|
||||
</div>
|
||||
|
||||
# 学之思在线考试系统 - Mysql版
|
||||
|
||||
## 项目介绍
|
||||
|
||||
学之思在线考试系统是一款 java + vue 的前后端分离的考试系统。主要优点是开发、部署简单快捷、界面设计友好、代码结构清晰。支持web端和微信小程序,能覆盖到pc机和手机等设备。
|
||||
支持多种部署方式:集成部署、前后端分离部署、docker部署。
|
||||
|
||||
### 开源版使用须知
|
||||
* 仅用个人学习,商用请购买授权 [http://www.mindskip.net/buy.html](http://www.mindskip.net/buy.html)
|
||||
* 禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负
|
||||
|
||||
* 仅用个人学习
|
||||
* 禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负
|
||||
|
||||
### 演示地址
|
||||
* 官网:[http://www.mindskip.net](http://www.mindskip.net)
|
||||
* 学之思:[http://www.mindskip.net/xzs.html](http://www.mindskip.net/xzs.html)
|
||||
* 学多多:[http://www.mindskip.net/xdd.html](http://www.mindskip.net/xdd.html)
|
||||
* 思多多:[http://www.mindskip.net/sdd.html](http://www.mindskip.net/sdd.html)
|
||||
|
||||
* 官网:[https://www.mindskip.net](https://www.mindskip.net)
|
||||
* 学之思考试系统:[https://www.mindskip.net/xzs.html](https://www.mindskip.net/xzs.html)
|
||||
* 思多多智能考试平台:[https://www.mindskip.net/sdd.html](https://www.mindskip.net/sdd.html)
|
||||
* 维多多培训考试系统:[https://www.mindskip.net/wdd.html](https://www.mindskip.net/wdd.html)
|
||||
* 学多多考试系统:[https://www.mindskip.net/xdd.html](https://www.mindskip.net/xdd.html)
|
||||
|
||||
### 学之思仓库版本地址
|
||||
|
||||
* gitee - postgresql :[https://gitee.com/mindskip/uexam](https://gitee.com/mindskip/uexam)
|
||||
* github - postgresql :[https://github.com/mindskip/xzs](https://github.com/mindskip/xzs)
|
||||
* gitee - mysql :[https://gitee.com/mindskip/xzs-mysql](https://gitee.com/mindskip/xzs-mysql)
|
||||
* github - postgresql :[https://github.com/mindskip/xzs](https://github.com/mindskip/xzs)
|
||||
* github - mysql :[https://github.com/mindskip/xzs-mysql](https://github.com/mindskip/xzs-mysql)
|
||||
|
||||
### 学之思交流群(加群获取数据库脚本)
|
||||
* 交流五群:`1074095891`
|
||||
|
||||
* QQ交流群八:`902855996`
|
||||
* QQ:`2693073475`
|
||||
* 微信:`alvis-u`
|
||||
|
||||
### 开发部署教程
|
||||
|
||||
### 大事件
|
||||
* 2020/5 思多多智能考试平台新版发布 地址:[http://www.mindskip.net/sdd.html](http://www.mindskip.net/sdd.html)
|
||||
* 2020/2 项目累计突破2000 star
|
||||
* 2020/1 累计超过150万用户使用
|
||||
* 2019/12 项目累计突破1000 star
|
||||
* 2019/11 入围开源中国最受欢迎开源项目
|
||||
* 2019/10 累计超过100万学生使用
|
||||
* 2019/10 荣获码云最有价值开源项目
|
||||
|
||||
* [https://www.mindskip.net:999](https://www.mindskip.net:999)
|
||||
|
||||
### 学生系统功能
|
||||
* 登录、注册: 注册时要选年级,过滤不同年级的试卷, 账号为student/123456
|
||||
|
||||
* 登录、注册: 注册时要选年级,过滤不同年级的试卷, 账号为:student/123456
|
||||
* 首页: 任务中心、固定试卷、时段试卷、可以能做的一部分试卷
|
||||
* 试卷中心: 包含了所有能做的试卷,按学科来过滤和分页
|
||||
* 考试记录: 所有的试卷考试记录在此处分页,可以查看试卷结果、用时、得分、自行批改等
|
||||
@ -47,56 +66,28 @@
|
||||
* 试卷答题和试卷查看: 展示出题目的基本信息和需要填写的内容
|
||||
|
||||
### 管理系统功能
|
||||
* 登录: 账号为 admin/123456
|
||||
|
||||
* 登录: 账号为: admin/123456
|
||||
* 主页: 包含了试卷、题目、做卷数、做题数、用户活跃度的统计功能,活跃度和做题数是按月统计
|
||||
* 用户管理: 对不同角色 学生、教师、管理员 的增删改查管理功能
|
||||
* 用户管理: 对不同角色 学生、管理员 的增删改查管理功能
|
||||
* 卷题管理:
|
||||
1. 试卷列表:试卷的增删改查,新增包含选择学科、试卷类型、试卷名称、考试时间,试卷内容包含添加大标题,然后添加题目到此试卷中,组成一套完整的试卷
|
||||
2. 题目列表:题目的增删改查,目前题型包含单选题、多选题、判断题、填空题、简单题,支持图片、公式等。
|
||||
* 任务管理:对任务进行修改
|
||||
* 教育管理:对不同年级的学科进行增删改查
|
||||
* 消息中心:可以对多个用户进行消息发送,预留:加入班级,推送试卷等消息
|
||||
* 消息中心:可以对多个用户进行消息发送
|
||||
* 日志中心:用户的基本操作进行日志记录,了解用户使用过情况
|
||||
|
||||
### 小程序学生系统功能:
|
||||
### 小程序功能
|
||||
|
||||
* 用户登录登出功能,登录会自动绑定微信账号,登出会解绑
|
||||
* 首页包含任务中心、固定试卷、时段试卷、推送试卷模块,和web端保持一致
|
||||
* 试卷模块,固定试卷和时段试卷的分页查询,下拉加载更多,上拉刷新当前数据
|
||||
* 记录模块,考试结果的分页,包含了试卷基本信息
|
||||
* 我的模块,包含个人资料的修改,个人动态,消息中心模块
|
||||
|
||||
|
||||
### 技术栈列表
|
||||
后台系统:
|
||||
* spring-boot 2.1.6.RELEASE
|
||||
* spring-boot-security 用户登录验证
|
||||
* undertow web容器
|
||||
* postgresql/mysql 优秀的开源数据库
|
||||
* redis 缓存,提升系统性能
|
||||
* mybatis 数据库中间件
|
||||
* hikari 速度最快的数据库连接池
|
||||
* 七牛云存储 目前10G内免费
|
||||
|
||||
前台系统:
|
||||
* Vue.js 采用新版,使用了vue-cli3搭建的系统,减少大量配置文件
|
||||
* element-ui 最流行的vue组件,采用的最新版
|
||||
* vue-element-admin 最新版,对该系统做了大量精简,只保留了部分样式和控件
|
||||
* echarts 图表统计
|
||||
* ueditor 填空题扩展插件
|
||||
|
||||
微信小程序:
|
||||
* iView 主题样式
|
||||
|
||||
### 使用教程
|
||||
1. redis 安装
|
||||
2. 进群获取到数据库脚本,创建表初始化数据
|
||||
3. /uexam/source/xzs为后台代码,建议使用IntelliJ IDEA打开,在application-dev.yml文件中,配置好postgesql/mysql、redis的服务地址,打开XzsApplication文件编译运行,默认端口为8000。
|
||||
4. 学生系统地址:http://localhost:8000/student
|
||||
5. 管理端地址:http://localhost:8000/admin
|
||||
|
||||
### 软件架构图
|
||||

|
||||
* 首页包含任务中心、固定试卷、时段试卷,和web端保持一致
|
||||
* 试卷模块:固定试卷和时段试卷的分页查询,下拉加载更多、上拉刷新当前数据
|
||||
* 记录模块:考试结果的分页,包含了试卷基本信息
|
||||
* 我的模块:包含个人资料的修改、个人动态、消息中心模块
|
||||
|
||||
### 系统展示
|
||||
|
||||
* 学生考试系统
|
||||
<table>
|
||||
<tr>
|
||||
@ -129,4 +120,3 @@
|
||||
<td><img src="doc/image/admin/13.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
Before Width: | Height: | Size: 551 KiB After Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 105 KiB |
BIN
doc/image/logo/1.png
Normal file
After Width: | Height: | Size: 36 KiB |
0
docs/.nojekyll
Normal file
BIN
docs/1.png
Normal file
After Width: | Height: | Size: 103 KiB |
356
docs/README.md
Normal file
@ -0,0 +1,356 @@
|
||||
# 目录
|
||||
|
||||
## 项目介绍
|
||||
|
||||
学之思在线考试系统是一款 java + vue 的前后端分离的考试系统。主要优点是开发、部署简单快捷、界面设计友好、代码结构清晰。支持web端和微信小程序,能覆盖到pc机和手机等设备。 支持多种部署方式:集成部署、前后端分离部署、docker部署。
|
||||
|
||||
## 开源版使用须知
|
||||
|
||||
仅用个人学习
|
||||
|
||||
禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负
|
||||
|
||||
## 学之思仓库地址
|
||||
|
||||
gitee - mysql :[https://gitee.com/mindskip/xzs-mysql](https://gitee.com/mindskip/xzs-mysql)
|
||||
|
||||
github - mysql :[https://github.com/mindskip/xzs-mysql](https://github.com/mindskip/xzs-mysql)
|
||||
|
||||
## 运行环境
|
||||
|
||||
| 环境 | 版本 |
|
||||
| ---- | ---- |
|
||||
| 操作系统 | Windows / Linux |
|
||||
| Jdk | 1.8 |
|
||||
| Redis | 6.0 |
|
||||
| Mysql | 8.0 |
|
||||
|
||||
## 技术栈列表
|
||||
|
||||
### 后台系统
|
||||
|
||||
* spring-boot 2.1.6.RELEASE
|
||||
* spring-boot-security 用户登录验证
|
||||
* undertow web容器
|
||||
* mysql 最流行的开源数据库
|
||||
* redis 缓存,提升系统性能
|
||||
* mybatis 数据库中间件
|
||||
* hikari 速度最快的数据库连接池
|
||||
* 七牛云存储 分布式文件存储中心
|
||||
|
||||
### 前台系统
|
||||
|
||||
* vue 采用新版,使用了vue-cli4搭建的系统,减少大量配置文件
|
||||
* element-ui 最流行的vue UI框架
|
||||
* vue-element-admin 深度定制版
|
||||
* echarts 图表统计
|
||||
* ueditor 深度定制版
|
||||
|
||||
### 微信小程序
|
||||
|
||||
* iView 主题样式
|
||||
|
||||
## 架构图
|
||||
|
||||

|
||||
|
||||
## 数据库设计
|
||||
|
||||
### 试卷表 t_exam_paper
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| name | varchar | 试卷名称 |
|
||||
| subject_id | int | 学科 |
|
||||
| paper_type | int | 试卷类型( 1固定试卷 4.时段试卷 6.任务试卷) |
|
||||
| grade_level | int | 年级 |
|
||||
| score | int | 试卷总分(千分制) |
|
||||
| question_count | int | 题目数量 |
|
||||
| suggest_time | int | 建议时长(分钟) |
|
||||
| limit_start_time | datetime | 时段试卷 开始时间 |
|
||||
| limit_end_time | datetime | 时段试卷 结束时间 |
|
||||
| frame_text_content_id | int | 试卷框架 内容为JSON |
|
||||
| create_user | int | |
|
||||
| create_time | datetime | |
|
||||
| deleted | bit | |
|
||||
| task_exam_id | int | |
|
||||
|
||||
### 试卷答案表 t_exam_paper_answer
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| exam_paper_id | int | |
|
||||
| paper_name | varchar | 试卷名称 |
|
||||
| paper_type | int | 试卷类型( 1固定试卷 2临时试卷 3班级试卷 4.时段试卷 ) |
|
||||
| subject_id | int | 学科 |
|
||||
| system_score | int | 系统判定得分 |
|
||||
| user_score | int | 最终得分(千分制) |
|
||||
| paper_score | int | 试卷总分 |
|
||||
| question_correct | int | 做对题目数量 |
|
||||
| question_count | int | 题目总数量 |
|
||||
| do_time | int | 做题时间(秒) |
|
||||
| status | int | 试卷状态(1待判分 2完成) |
|
||||
| create_user | int | 学生 |
|
||||
| create_time | datetime | 提交时间 |
|
||||
| task_exam_id | int | |
|
||||
|
||||
### 试卷题目答案表 t_exam_paper_question_customer_answer
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| question_id | int | 题目Id |
|
||||
| exam_paper_id | int | 答案Id |
|
||||
| exam_paper_answer_id | int | |
|
||||
| question_type | int | 题型 |
|
||||
| subject_id | int | 学科 |
|
||||
| customer_score | int | 得分 |
|
||||
| question_score | int | 题目原始分数 |
|
||||
| question_text_content_id | int | 问题内容 |
|
||||
| answer | varchar | 做题答案 |
|
||||
| text_content_id | int | 做题内容 |
|
||||
| do_right | bit | 是否正确 |
|
||||
| create_user | int | 做题人 |
|
||||
| create_time | datetime | |
|
||||
| item_order | int | |
|
||||
|
||||
### 消息表 t_message
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| title | varchar | 标题 |
|
||||
| content | varchar | 内容 |
|
||||
| create_time | datetime | |
|
||||
| send_user_id | int | 发送者用户ID |
|
||||
| send_user_name | varchar | 发送者用户名 |
|
||||
| send_real_name | varchar | 发送者真实姓名 |
|
||||
| receive_user_count | int | 接收人数 |
|
||||
| read_count | int | 已读人数 |
|
||||
|
||||
### 用户消息表 t_message_user
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| message_id | int | 消息内容ID |
|
||||
| receive_user_id | int | 接收人ID |
|
||||
| receive_user_name | varchar | 接收人用户名 |
|
||||
| receive_real_name | varchar | 接收人真实姓名 |
|
||||
| readed | bit | 是否已读 |
|
||||
| create_time | datetime | |
|
||||
| read_time | datetime | 阅读时间 |
|
||||
|
||||
### 题目表 t_question
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| question_type | int | 1.单选题 2.多选题 3.判断题 4.填空题 5.简答题 |
|
||||
| subject_id | int | 学科 |
|
||||
| score | int | 题目总分(千分制) |
|
||||
| grade_level | int | 级别 |
|
||||
| difficult | int | 题目难度 |
|
||||
| correct | text | 正确答案 |
|
||||
| info_text_content_id | int | 题目 填空、 题干、解析、答案等信息 |
|
||||
| create_user | int | 创建人 |
|
||||
| status | int | 1.正常 |
|
||||
| create_time | datetime | 创建时间 |
|
||||
| deleted | bit | |
|
||||
|
||||
### 学科表 t_subject
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| name | varchar | 语文 数学 英语 等 |
|
||||
| level | int | 年级 (1-12) 小学 初中 高中 大学 |
|
||||
| level_name | varchar | 一年级、二年级等 |
|
||||
| item_order | int | 排序 |
|
||||
| deleted | bit | |
|
||||
|
||||
### 任务表 t_task_exam
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| title | varchar | |
|
||||
| grade_level | int | 级别 |
|
||||
| frame_text_content_id | int | 任务框架 内容为JSON |
|
||||
| create_user | int | |
|
||||
| create_time | datetime | |
|
||||
| deleted | bit | |
|
||||
| create_user_name | varchar | |
|
||||
|
||||
### 用户任务表 t_task_exam_customer_answer
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| task_exam_id | int | |
|
||||
| create_user | int | |
|
||||
| create_time | datetime | |
|
||||
| text_content_id | int | 任务完成情况(Json) |
|
||||
|
||||
### 文本表 t_text_content
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| content | text | |
|
||||
| create_time | datetime | |
|
||||
|
||||
### 用户表 t_user
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| user_uuid | varchar | |
|
||||
| user_name | varchar | 用户名 |
|
||||
| password | varchar | |
|
||||
| real_name | varchar | 真实姓名 |
|
||||
| age | int | |
|
||||
| sex | int | 1.男 2女 |
|
||||
| birth_day | datetime | |
|
||||
| user_level | int | 学生年级(1-12) |
|
||||
| phone | varchar | |
|
||||
| role | int | 1.学生 2.老师 3.管理员 |
|
||||
| status | int | 1.启用 2禁用 |
|
||||
| image_path | varchar | 头像地址 |
|
||||
| create_time | datetime | |
|
||||
| modify_time | datetime | |
|
||||
| last_active_time | datetime | |
|
||||
| deleted | bit | 是否删除 |
|
||||
| wx_open_id | varchar | 微信openId |
|
||||
|
||||
### 用户日志表 t_user_event_log
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| user_id | int | 用户id |
|
||||
| user_name | varchar | 用户名 |
|
||||
| real_name | varchar | 真实姓名 |
|
||||
| content | text | 内容 |
|
||||
| create_time | datetime | 时间 |
|
||||
|
||||
### 用户Token表 t_user_token
|
||||
|
||||
| 字段名 | 类型 | 注释 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | int | |
|
||||
| token | varchar | |
|
||||
| user_id | int | 用户Id |
|
||||
| wx_open_id | varchar | 微信openId |
|
||||
| create_time | datetime | |
|
||||
| end_time | datetime | |
|
||||
| user_name | varchar | 用户名 |
|
||||
|
||||
## 项目开发
|
||||
|
||||
### 开发说明
|
||||
|
||||
* redis 安装
|
||||
* 进群获取到数据库脚本,创建表初始化数据,数据库名称为xzs
|
||||
* 代码分为 mysql版本,配合相应的数据库使用
|
||||
* 安装mysql ,导入xzs-mysql.sql脚本。
|
||||
* 学生端默认账号:student / 123456
|
||||
* 管理端默认账号:admin / 123456
|
||||
|
||||
### 后端开发
|
||||
|
||||
* /uexam/source/xzs为后台代码,建议使用IntelliJ IDEA打开
|
||||
* 打开application-dev.yml文件中,配置好postgesql/mysql、redis的服务地址
|
||||
* 去七牛云官网申请好云存储账号,修改application.yml中的qn相关的配置
|
||||
* 启动后台程序,默认端口为8000。
|
||||
* 学生系统地址:<http://ip:8000/student>
|
||||
* 管理端地址:<http://ip:8000/admin>
|
||||
|
||||
### 前端开发
|
||||
|
||||
* 前端使用webstorm或者vscode,分别打开文件夹打开源代码\source\vue\xzs-student和source\vue\xzs-admin
|
||||
* 执行下面2个命令,安装node_module:
|
||||
|
||||
```npm
|
||||
npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
|
||||
npm install --registry https://registry.npm.taobao.org
|
||||
```
|
||||
|
||||
* 执行下面命令,启动前端代码
|
||||
|
||||
```npm
|
||||
npm run serve
|
||||
```
|
||||
|
||||
* 打包命名
|
||||
|
||||
```npm
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 微信小程序开发
|
||||
|
||||
* 去腾讯小程序官网注册账号,拿到appid和secret信息
|
||||
* 下载好微信小程序开发工具
|
||||
* 打开工具,导入代码 \source\wx\xzs-student
|
||||
* 修改application.yml文件里的wx配置下面的appid和secret
|
||||
* 启动小程序开发工具
|
||||
|
||||
## 项目部署
|
||||
|
||||
### 集成部署
|
||||
|
||||
* 分别在\source\vue\xzs-student目录和source\vue\xzs-admin目录,执行前端打包命令
|
||||
|
||||
```npm
|
||||
npm run build
|
||||
```
|
||||
|
||||
* 打包后的目录为student和admin
|
||||
* 将文件放到\source\xzs\src\main\resources\static下,然后将java程序打包成jar包
|
||||
* 修改application-prod.yml中的datasource和redis地址
|
||||
* 学生端访问地址为:<http://ip:8000/student>
|
||||
* 管理员端访问地址为:<http://ip:8000/admin>
|
||||
* 执行下列命令,运行程序
|
||||
|
||||
```java
|
||||
nohup java -Duser.timezone=Asia/Shanghai -jar -Dspring.profiles.active=prod xzs-3.2.0.jar > start1.log 2>&1 &
|
||||
```
|
||||
|
||||
### 前后端分离部署
|
||||
|
||||
* 采用前后端分离方式部署,后端启动和部署方式1一样
|
||||
* 前端采用nginx来装载静态页面,先创建/usr/local/xzs/web/目录,然后将打包后的student、admin放到此目录下
|
||||
* 页面访问端口为8001,注意检查防火墙端口是否打开
|
||||
* 学生端访问地址为:<http://ip:8001/student>
|
||||
* 管理员端访问地址为:<http://ip:8001/admin>
|
||||
* nginx配置如下:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 8001;
|
||||
server_name xzs;
|
||||
location / {
|
||||
root /usr/local/xzs/web/;
|
||||
index index.html;
|
||||
}
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:8000;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### docker部署
|
||||
|
||||
* 先检查服务器端口、ip转发的是否配置正确,否则无法访问到docker内部
|
||||
* docker内部镜像已经安装了java、mysql、redis、nginx,均已配置好,无需其他操作
|
||||
* 执行下列docker命令,拉取镜像,启动容器
|
||||
* 学生端访问地址为:<http://ip:8001/student>
|
||||
* 管理员端访问地址为:<http://ip:8001/admin>
|
||||
|
||||
```docker
|
||||
docker pull registry.cn-hangzhou.aliyuncs.com/mindskip/xzs:v3.2.0
|
||||
docker run -d --name xzs --privileged -it -d -p 8001:8001 -v /etc/localtime:/etc/localtime:ro registry.cn-hangzhou.aliyuncs.com/mindskip/xzs:v3.2.0 /usr/sbin/init
|
||||
```
|
7
docs/_coverpage.md
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
# 学之思考试系统
|
||||
|
||||
> 学之思在线考试系统是一款 java + vue 的前后端分离的考试系统。主要优点是开发、部署简单快捷、界面设计友好、代码结构清晰。支持web端和微信小程序,能覆盖到pc机和手机等设备。 支持多种部署方式:集成部署、前后端分离部署、docker部署。
|
||||
|
||||
[Gitee](https://gitee.com/mindskip/uexam)
|
||||
[Get Started](#目录)
|
1
docs/docsify@4.js
Normal file
BIN
docs/favicon.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
42
docs/index.html
Normal file
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>学之思开发部署教程</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="vue.css">
|
||||
<link rel="stylesheet" href="xzs.css">
|
||||
<link rel="shortcut icon" href="favicon.png">
|
||||
</head>
|
||||
|
||||
<body style="min-width: 1024px;">
|
||||
<nav class="head">
|
||||
<div class="head-logo">
|
||||
<a href="https://www.mindskip.net" target="_blank">
|
||||
<img src="logo.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="head-link">
|
||||
<a href="https://www.mindskip.net/" target="_blank">官网</a>
|
||||
<a href="https://www.mindskip.net/sdd.html" target="_blank">思多多</a>
|
||||
<a href="https://www.mindskip.net/wdd.html" target="_blank">维多多</a>
|
||||
<a href="https://www.mindskip.net/xdd.html" target="_blank">学多多</a>
|
||||
<a href="https://www.mindskip.net/xzs.html" target="_blank">学之思</a>
|
||||
<a href="https://www.mindskip.net/buy.html" target="_blank">商业购买</a>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: '学之思开发部署教程',
|
||||
coverpage: false
|
||||
}
|
||||
</script>
|
||||
<!-- Docsify v4 -->
|
||||
<script src="docsify@4.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
docs/logo.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
1005
docs/vue.css
Normal file
39
docs/xzs.css
Normal file
@ -0,0 +1,39 @@
|
||||
table th {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
table td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin: 0px !important;
|
||||
line-height: 58px;
|
||||
padding: 10px 20px;
|
||||
background-color: #f8f8f8;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.head-logo {
|
||||
height: 58px;
|
||||
width: 182px;
|
||||
line-height: 78px;
|
||||
}
|
||||
|
||||
.head-link {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.head-link a {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 80px !important;
|
||||
}
|
13617
source/vue/xzs-admin/package-lock.json
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "xzs-admin",
|
||||
"version": "3.0.7",
|
||||
"author": "武汉思维跳跃科技",
|
||||
"version": "3.3.0",
|
||||
"author": "武汉思维跳跃科技有限公司",
|
||||
"description": "学之思管理系统",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
@ -16,22 +16,22 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"core-js": "^3.6.5",
|
||||
"element-ui": "^2.13.2",
|
||||
"core-js": "^3.9.0",
|
||||
"element-ui": "^2.15.0",
|
||||
"js-cookie": "2.2.0",
|
||||
"normalize.css": "8.0.1",
|
||||
"nprogress": "0.2.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-count-to": "^1.0.13",
|
||||
"vue-router": "^3.3.4",
|
||||
"vuex": "^3.5.1"
|
||||
"vue-router": "^3.5.1",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.4.6",
|
||||
"@vue/cli-plugin-eslint": "^4.4.6",
|
||||
"@vue/cli-plugin-router": "^4.4.6",
|
||||
"@vue/cli-plugin-vuex": "^4.4.6",
|
||||
"@vue/cli-service": "^4.4.6",
|
||||
"@vue/cli-plugin-babel": "^4.5.11",
|
||||
"@vue/cli-plugin-eslint": "^4.5.11",
|
||||
"@vue/cli-plugin-router": "^4.5.11",
|
||||
"@vue/cli-plugin-vuex": "^4.5.11",
|
||||
"@vue/cli-service": "^4.5.11",
|
||||
"@vue/eslint-config-standard": "^4.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^5.16.0",
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
|
5
source/vue/xzs-admin/src/api/examPaperAnwser.js
Normal file
@ -0,0 +1,5 @@
|
||||
import { post } from '@/utils/request'
|
||||
|
||||
export default {
|
||||
page: query => post('/api/admin/examPaperAnswer/page', query)
|
||||
}
|
1
source/vue/xzs-admin/src/icons/svg/answer.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569065326528" class="icon" viewBox="0 0 1152 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3178" xmlns:xlink="http://www.w3.org/1999/xlink" width="225" height="200"><defs><style type="text/css"></style></defs><path d="M1023.584 0 128.416 0C57.472 0 0 57.504 0 128.416L0 767.584C0 838.496 57.472 896 128.416 896L192 896 192 985.856C192 1007.904 210.08 1024 230.112 1024 235.552 1024 241.12 1022.816 246.528 1020.256L480.544 908.48C497.76 900.256 516.608 896 535.68 896L1023.584 896C1094.496 896 1152 838.496 1152 767.584L1152 128.416C1152 57.504 1094.496 0 1023.584 0ZM319.9936 352C319.9936 334.32689 334.221792 320 352.021504 320L799.965696 320C817.654208 320 831.9936 334.203674 831.9936 352 831.9936 369.67311 817.765408 384 799.965696 384L352.021504 384C334.332992 384 319.9936 369.796326 319.9936 352ZM319.9936 544C319.9936 526.32689 334.221792 512 352.021504 512L799.965696 512C817.654208 512 831.9936 526.203674 831.9936 544 831.9936 561.67311 817.765408 576 799.965696 576L352.021504 576C334.332992 576 319.9936 561.796326 319.9936 544Z" p-id="3179"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<app-main />
|
||||
<div class="foot-copyright">
|
||||
<span>Copyright © 2020 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
<span>Copyright © 2021 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
</div>
|
||||
<back-to-top :visibility-height="100" :back-position="0" transition-name="fade" ref="backTop"/>
|
||||
</div>
|
||||
|
@ -187,6 +187,24 @@ const constantRoutes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/answer',
|
||||
component: Layout,
|
||||
name: 'AnswerPage',
|
||||
meta: {
|
||||
title: '成绩管理',
|
||||
icon: 'answer'
|
||||
},
|
||||
alwaysShow: true,
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
component: () => import('@/views/answer/list'),
|
||||
name: 'AnswerPageList',
|
||||
meta: { title: '答卷列表', noCache: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/message',
|
||||
component: Layout,
|
||||
|
96
source/vue/xzs-admin/src/views/answer/list.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="学科:" >
|
||||
<el-select v-model="queryParam.subjectId" clearable>
|
||||
<el-option v-for="item in subjects" :key="item.id" :value="item.id" :label="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" width="100" />
|
||||
<el-table-column prop="paperName" label="试卷名称"/>
|
||||
<el-table-column prop="userName" label="用户名称"/>
|
||||
<el-table-column label="得分" width="100px" >
|
||||
<template slot-scope="{row}">
|
||||
{{row.userScore}} / {{row.paperScore}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="题目对错" width="80px" >
|
||||
<template slot-scope="{row}">
|
||||
{{row.questionCorrect}} / {{row.questionCount}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="doTime" label="耗时" width="100px"/>
|
||||
<el-table-column prop="createTime" label="提交时间" width="160px"/>
|
||||
<el-table-column label="操作" width="160px">
|
||||
<template slot-scope="scope" >
|
||||
<el-button v-show="scope.row.status == 1" type="primary" round @click="toedit(scope.row.id,1)">批改</el-button>
|
||||
<el-button v-show="scope.row.status == 2" type="primary" round @click="toedit(scope.row.id,0)">查看试卷</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import examPaperAnswerApi from '@/api/examPaperAnwser'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
subjectId: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: false,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.initSubject()
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
examPaperAnswerApi.page(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
toedit(id,type){
|
||||
if(type == 1){
|
||||
window.open("/student/index.html#/edit?id=" + id)
|
||||
}else{
|
||||
window.open("/student/index.html#/read?id=" + id)
|
||||
}
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapGetters('exam', ['subjectEnumFormat']),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
@ -65,7 +65,15 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
name: '',
|
||||
level: 1,
|
||||
levelName: ''
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
|
@ -238,7 +238,19 @@ export default {
|
||||
return this.subjectEnumFormat(cellValue)
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
level: null,
|
||||
subjectId: null,
|
||||
paperType: 1,
|
||||
limitDateTime: [],
|
||||
name: '',
|
||||
suggestTime: null,
|
||||
titleItems: []
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
|
@ -208,7 +208,22 @@ export default {
|
||||
this.questionShow.question = this.form
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
questionType: 4,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
|
@ -195,7 +195,27 @@ export default {
|
||||
this.questionShow.question = this.form
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
questionType: 2,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
{ id: null, prefix: 'A', content: '' },
|
||||
{ id: null, prefix: 'B', content: '' },
|
||||
{ id: null, prefix: 'C', content: '' },
|
||||
{ id: null, prefix: 'D', content: '' }
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
correctArray: [],
|
||||
score: '',
|
||||
difficult: 0
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
|
@ -161,7 +161,21 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
questionType: 5,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
|
@ -157,8 +157,13 @@ export default {
|
||||
},
|
||||
questionItemAdd () {
|
||||
let items = this.form.items
|
||||
let last = items[items.length - 1]
|
||||
let newLastPrefix = String.fromCharCode(last.prefix.charCodeAt() + 1)
|
||||
let newLastPrefix
|
||||
if (items.length > 0) {
|
||||
let last = items[items.length - 1]
|
||||
newLastPrefix = String.fromCharCode(last.prefix.charCodeAt() + 1)
|
||||
} else {
|
||||
newLastPrefix = 'A'
|
||||
}
|
||||
items.push({ id: null, prefix: newLastPrefix, content: '' })
|
||||
},
|
||||
submitForm () {
|
||||
@ -185,7 +190,26 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
questionType: 1,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
{ prefix: 'A', content: '' },
|
||||
{ prefix: 'B', content: '' },
|
||||
{ prefix: 'C', content: '' },
|
||||
{ prefix: 'D', content: '' }
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
|
@ -172,7 +172,24 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
questionType: 3,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
{ id: null, prefix: 'A', content: '是' },
|
||||
{ id: null, prefix: 'B', content: '否' }
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
|
@ -52,7 +52,7 @@
|
||||
</el-form>
|
||||
|
||||
<div class="account-foot-copyright">
|
||||
<span>Copyright © 2020 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
<span>Copyright © 2021 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -89,9 +89,14 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.options = []
|
||||
this.form.receiveUserIds = []
|
||||
this.form = {
|
||||
title: '',
|
||||
content: '',
|
||||
receiveUserIds: []
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
}
|
||||
|
@ -175,7 +175,15 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
gradeLevel: null,
|
||||
title: '',
|
||||
paperItems: []
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
subjectFormatter (row, column, cellValue, index) {
|
||||
return this.subjectEnumFormat(cellValue)
|
||||
|
@ -20,7 +20,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker v-model="form.birthDay" type="date" placeholder="选择日期"/>
|
||||
<el-date-picker v-model="form.birthDay" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机:">
|
||||
<el-input v-model="form.phone"></el-input>
|
||||
@ -104,7 +104,21 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
userName: '',
|
||||
password: '',
|
||||
realName: '',
|
||||
role: 3,
|
||||
status: 1,
|
||||
age: '',
|
||||
sex: '',
|
||||
birthDay: null,
|
||||
phone: null
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
|
@ -20,7 +20,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker v-model="form.birthDay" type="date" placeholder="选择日期" />
|
||||
<el-date-picker v-model="form.birthDay" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机:">
|
||||
<el-input v-model="form.phone"></el-input>
|
||||
@ -113,7 +113,22 @@ export default {
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
let lastId = this.form.id
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: null,
|
||||
userName: '',
|
||||
password: '',
|
||||
realName: '',
|
||||
role: 1,
|
||||
status: 1,
|
||||
age: '',
|
||||
sex: '',
|
||||
birthDay: null,
|
||||
phone: null,
|
||||
userLevel: null
|
||||
}
|
||||
this.form.id = lastId
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
|
@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="用户名:" prop="userName" required>
|
||||
<el-input v-model="form.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码:" required>
|
||||
<el-input v-model="form.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="真实姓名:" prop="realName" required>
|
||||
<el-input v-model="form.realName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年龄:">
|
||||
<el-input v-model="form.age"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:">
|
||||
<el-select v-model="form.sex" placeholder="性别" clearable>
|
||||
<el-option v-for="item in sexEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker v-model="form.birthDay" type="date" placeholder="选择日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机:">
|
||||
<el-input v-model="form.phone"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态:" required>
|
||||
<el-select v-model="form.status" placeholder="状态">
|
||||
<el-option v-for="item in statusEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
userName: '',
|
||||
password: '',
|
||||
realName: '',
|
||||
role: 2,
|
||||
status: 1,
|
||||
age: '',
|
||||
sex: '',
|
||||
birthDay: null,
|
||||
phone: null
|
||||
},
|
||||
formLoading: false,
|
||||
rules: {
|
||||
userName: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' }
|
||||
],
|
||||
realName: [
|
||||
{ required: true, message: '请输入真实姓名', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
userApi.selectUser(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
userApi.createUser(this.form).then(data => {
|
||||
if (data.code === 1) {
|
||||
_this.$message.success(data.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/user/teacher/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(data.message)
|
||||
_this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
_this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
roleEnum: state => state.user.roleEnum,
|
||||
statusEnum: state => state.user.statusEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,131 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="用户名:">
|
||||
<el-input v-model="queryParam.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
<router-link :to="{path:'/user/teacher/edit'}" class="link-left">
|
||||
<el-button type="primary">添加</el-button>
|
||||
</router-link>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" />
|
||||
<el-table-column prop="userName" label="用户名"/>
|
||||
<el-table-column prop="realName" label="真实姓名" />
|
||||
<el-table-column prop="sex" label="性别" width="60px;" :formatter="sexFormatter"/>
|
||||
<el-table-column prop="phone" label="手机号"/>
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="状态" prop="status" width="70px">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag :type="statusTagFormatter(row.status)">
|
||||
{{ statusFormatter(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="220px" label="操作" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" @click="changeStatus(row)" class="link-left">
|
||||
{{ statusBtnFormatter(row.status) }}
|
||||
</el-button>
|
||||
<router-link :to="{path:'/user/teacher/edit', query:{id:row.id}}" class="link-left">
|
||||
<el-button size="mini" >编辑</el-button>
|
||||
</router-link>
|
||||
<el-button size="mini" type="danger" @click="deleteUser(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
userName: '',
|
||||
role: 2,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
userApi.getUserPageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
changeStatus (row) {
|
||||
let _this = this
|
||||
userApi.changeStatus(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
row.status = re.response
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteUser (row) {
|
||||
let _this = this
|
||||
userApi.deleteUser(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
sexFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.sexEnum, cellValue)
|
||||
},
|
||||
statusFormatter (status) {
|
||||
return this.enumFormat(this.statusEnum, status)
|
||||
},
|
||||
statusTagFormatter (status) {
|
||||
return this.enumFormat(this.statusTag, status)
|
||||
},
|
||||
statusBtnFormatter (status) {
|
||||
return this.enumFormat(this.statusBtn, status)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
statusEnum: state => state.user.statusEnum,
|
||||
statusTag: state => state.user.statusTag,
|
||||
statusBtn: state => state.user.statusBtn
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
@ -19,7 +19,7 @@ module.exports = {
|
||||
hotOnly: false,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8000',
|
||||
target: 'http://129.211.1.159:8080',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
|
9520
source/vue/xzs-admin/yarn.lock
Normal file
13612
source/vue/xzs-student/package-lock.json
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "xzs-student",
|
||||
"version": "3.0.7",
|
||||
"author": "武汉思维跳跃科技",
|
||||
"version": "3.3.0",
|
||||
"author": "武汉思维跳跃科技有限公司",
|
||||
"description": "学之思考试系统",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
@ -16,26 +16,26 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"core-js": "^3.4.4",
|
||||
"element-ui": "^2.13.2",
|
||||
"core-js": "^3.8.3",
|
||||
"element-ui": "^2.15.0",
|
||||
"js-cookie": "2.2.0",
|
||||
"normalize.css": "8.0.1",
|
||||
"nprogress": "0.2.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-router": "^3.3.4",
|
||||
"vuex": "^3.5.1"
|
||||
"vue-router": "^3.5.1",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.4.6",
|
||||
"@vue/cli-plugin-eslint": "^4.4.6",
|
||||
"@vue/cli-plugin-router": "^4.4.6",
|
||||
"@vue/cli-plugin-vuex": "^4.4.6",
|
||||
"@vue/cli-service": "^4.4.6",
|
||||
"@vue/cli-plugin-babel": "^4.5.11",
|
||||
"@vue/cli-plugin-eslint": "^4.5.11",
|
||||
"@vue/cli-plugin-router": "^4.5.11",
|
||||
"@vue/cli-plugin-vuex": "^4.5.11",
|
||||
"@vue/cli-service": "^4.5.11",
|
||||
"@vue/eslint-config-standard": "^4.0.0",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"node-sass": "^4.0.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"svg-sprite-loader": "4.1.6",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 26 KiB |
BIN
source/vue/xzs-student/src/assets/code/1.jpg
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
source/vue/xzs-student/src/assets/code/2.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
source/vue/xzs-student/src/assets/code/3.jpg
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
source/vue/xzs-student/src/assets/code/4.jpg
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
source/vue/xzs-student/src/assets/code/5.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
source/vue/xzs-student/src/assets/code/6.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
source/vue/xzs-student/src/assets/code/7.jpg
Normal file
After Width: | Height: | Size: 87 KiB |
@ -35,10 +35,24 @@
|
||||
<div class="container">
|
||||
<div class="footer-main">
|
||||
<h4>产品介绍</h4>
|
||||
<a href="http://www.mindskip.net" target="_blank" class="footer-main-link">思维跳跃科技</a>
|
||||
<a href="http://www.mindskip.net/sdd.html" target="_blank" class="footer-main-link">思多多智能考试平台</a>
|
||||
<a href="http://www.mindskip.net/xdd.html" target="_blank" class="footer-main-link">学多多考试系统</a>
|
||||
<a href="http://www.mindskip.net/xzs.html" target="_blank" class="footer-main-link">学之思考试系统</a>
|
||||
<a href="https://www.mindskip.net/sdd.html" target="_blank" class="footer-main-link">思多多智能考试平台</a>
|
||||
<a href="https://www.mindskip.net/wdd.html" target="_blank" class="footer-main-link">维多多培训考试系统</a>
|
||||
<a href="https://www.mindskip.net/xdd.html" target="_blank" class="footer-main-link">学多多考试系统</a>
|
||||
<a href="https://www.mindskip.net/xzs.html" target="_blank" class="footer-main-link">学之思考试系统</a>
|
||||
</div>
|
||||
<div class="footer-main">
|
||||
<h4>学多多小程序</h4>
|
||||
<img src="@/assets/code/1.jpg" style="width: 100px;height: 100px;"/>
|
||||
</div>
|
||||
<div class="footer-main">
|
||||
<h4>跃考 H5、小程序</h4>
|
||||
<img src="@/assets/code/2.png" style="width: 100px;height: 100px;"/>
|
||||
<img src="@/assets/code/3.jpg" style="width: 100px;height: 100px;margin-left: 10px"/>
|
||||
</div>
|
||||
<div class="footer-main">
|
||||
<h4>维考 H5、小程序</h4>
|
||||
<img src="@/assets/code/6.png" style="width: 100px;height: 100px;"/>
|
||||
<img src="@/assets/code/7.jpg" style="width: 100px;height: 100px;margin-left: 10px"/>
|
||||
</div>
|
||||
<div class="footer-main">
|
||||
<h4>关于我们</h4>
|
||||
@ -52,7 +66,7 @@
|
||||
</div>
|
||||
</el-footer>
|
||||
<div class="foot-copyright">
|
||||
<span>Copyright © 2020 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
<span>Copyright © 2021 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
</div>
|
||||
</el-container>
|
||||
</template>
|
||||
|
@ -89,7 +89,7 @@ html {
|
||||
.footer-main {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-right: 110px;
|
||||
margin-right: 70px;
|
||||
|
||||
.footer-main-link {
|
||||
display: block;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import vue from 'vue'
|
||||
|
||||
const request = function (loadtip, query) {
|
||||
let loading
|
||||
if (loadtip) {
|
||||
|
@ -50,8 +50,8 @@
|
||||
</el-row>
|
||||
<el-row class="app-item-contain">
|
||||
<h3 class="index-title-h3">固定试卷</h3>
|
||||
<div style="padding-left: 15px">
|
||||
<el-col :span="4" v-for="(item, index) in fixedPaper" :key="index" :offset="index > 0 ? 1 : 0">
|
||||
<div style="padding-left: 15px;display: flex;flex-wrap: wrap;">
|
||||
<el-col style="float: unset;" :span="4" v-for="(item, index) in fixedPaper" :key="index" :offset="index > 0 ? 1 : 0">
|
||||
<el-card :body-style="{ padding: '0px' }" v-loading="loading">
|
||||
<img src="@/assets/exam-paper/show1.png" class="image">
|
||||
<div style="padding: 14px;">
|
||||
|
@ -67,10 +67,13 @@
|
||||
<span v-html="question.analyze" class="q-item-span-content" />
|
||||
</div>
|
||||
<div class="question-answer-show-item">
|
||||
<span class="question-show-item">正确答案:</span>
|
||||
<span :class="{'question-show-item': qType!=4}">正确答案:</span>
|
||||
<span v-if="qType==1||qType==2 ||qType==5" v-html="question.correct" class="q-item-span-content"/>
|
||||
<span v-if="qType==3" v-html="trueFalseFormatter(question)" class="q-item-span-content"/>
|
||||
<span v-if="qType==4">{{question.correctArray}}</span>
|
||||
<!-- <span v-if="qType==4" v-for="(item,key) in question.correctArray" :key="key" v-html="item"></span> -->
|
||||
<ol v-if="qType==4">
|
||||
<li v-for="(item,key) in question.correctArray" :key="key" v-html="item"></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
|
@ -95,7 +95,7 @@ export default {
|
||||
_this.$alert('试卷得分:' + re.response + '分', '考试结果', {
|
||||
confirmButtonText: '返回考试记录',
|
||||
callback: action => {
|
||||
_this.$router.push('/record/index')
|
||||
window.close()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
|
@ -31,7 +31,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="account-foot-copyright">
|
||||
<span>Copyright © 2020 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
<span>Copyright © 2021 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -16,10 +16,11 @@
|
||||
<el-table-column prop="createTime" label="做题时间" width="170" />
|
||||
<el-table-column align="right" width="70">
|
||||
<template slot-scope="{row}">
|
||||
<router-link target="_blank" :to="{path:'/edit',query:{id:row.id}}" v-if="row.status === 1 ">
|
||||
<!-- <router-link target="_blank" :to="{path:'/edit',query:{id:row.id}}" v-if="row.status === 1 ">
|
||||
<el-button type="text" size="small">批改</el-button>
|
||||
</router-link>
|
||||
<router-link target="_blank" :to="{path:'/read',query:{id:row.id}}" v-if="row.status === 2 ">
|
||||
</router-link> -->
|
||||
<!-- v-if="row.status === 2 -->
|
||||
<router-link target="_blank" :to="{path:'/read',query:{id:row.id}}">
|
||||
<el-button type="text" size="small">查看试卷</el-button>
|
||||
</router-link>
|
||||
</template>
|
||||
|
@ -37,7 +37,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="account-foot-copyright">
|
||||
<span>Copyright © 2020 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
<span>Copyright © 2021 武汉思维跳跃科技有限公司 版权所有</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -51,7 +51,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker v-model="form.birthDay" type="date" placeholder="选择日期"/>
|
||||
<el-date-picker v-model="form.birthDay" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机:">
|
||||
<el-input v-model="form.phone"></el-input>
|
||||
|
@ -19,7 +19,7 @@ module.exports = {
|
||||
hotOnly: false,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8000',
|
||||
target: 'http://129.211.1.159:8080',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
|
9515
source/vue/xzs-student/yarn.lock
Normal file
@ -5,11 +5,11 @@
|
||||
|
||||
<groupId>com.mindskip</groupId>
|
||||
<artifactId>xzs</artifactId>
|
||||
<version>3.0.7</version>
|
||||
<version>3.2.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>xzs</name>
|
||||
<description>武汉思维跳跃科技-学之思考试系统</description>
|
||||
<description>学之思考试系统 - 武汉思维跳跃科技有限公司</description>
|
||||
|
||||
|
||||
<properties>
|
||||
@ -118,13 +118,6 @@
|
||||
<version>2.3.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
|
@ -8,7 +8,7 @@ import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableTransactionManagement
|
||||
|
@ -8,7 +8,7 @@ import org.modelmapper.ModelMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
public class BaseApiController {
|
||||
protected final static String DEFAULT_PAGE_SIZE = "10";
|
||||
|
@ -2,7 +2,7 @@ package com.mindskip.xzs.base;
|
||||
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
public abstract class BaseEntity {
|
||||
|
||||
|
@ -1,15 +1,29 @@
|
||||
package com.mindskip.xzs.base;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class BasePage {
|
||||
|
||||
private Integer pageIndex;
|
||||
|
||||
private Integer pageSize;
|
||||
|
||||
public Integer getPageIndex() {
|
||||
return pageIndex;
|
||||
}
|
||||
|
||||
public void setPageIndex(Integer pageIndex) {
|
||||
this.pageIndex = pageIndex;
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.mindskip.xzs.base;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
public class RestResponse<T> {
|
||||
private int code;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.mindskip.xzs.base;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
public enum SystemCode {
|
||||
/**
|
||||
|
@ -6,7 +6,7 @@ import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
@Component
|
||||
public class ApplicationContextProvider implements ApplicationContextAware {
|
||||
|
@ -3,7 +3,7 @@ package com.mindskip.xzs.configuration.property;
|
||||
public class CookieConfig {
|
||||
|
||||
public static String getName() {
|
||||
return "exam";
|
||||
return "xzs";
|
||||
}
|
||||
|
||||
public static Integer getInterval() {
|
||||
|
@ -1,9 +1,25 @@
|
||||
package com.mindskip.xzs.configuration.property;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PasswordKeyConfig {
|
||||
private String publicKey;
|
||||
|
||||
private String privateKey;
|
||||
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void setPublicKey(String publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,46 @@
|
||||
package com.mindskip.xzs.configuration.property;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class QnConfig {
|
||||
|
||||
private String url;
|
||||
private String bucket;
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getBucket() {
|
||||
return bucket;
|
||||
}
|
||||
|
||||
public void setBucket(String bucket) {
|
||||
this.bucket = bucket;
|
||||
}
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,51 @@
|
||||
package com.mindskip.xzs.configuration.property;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "system")
|
||||
@Data
|
||||
public class SystemConfig {
|
||||
|
||||
private PasswordKeyConfig pwdKey;
|
||||
private List<String> securityIgnoreUrls;
|
||||
private WxConfig wx;
|
||||
private QnConfig qn;
|
||||
|
||||
public PasswordKeyConfig getPwdKey() {
|
||||
return pwdKey;
|
||||
}
|
||||
|
||||
public void setPwdKey(PasswordKeyConfig pwdKey) {
|
||||
this.pwdKey = pwdKey;
|
||||
}
|
||||
|
||||
public List<String> getSecurityIgnoreUrls() {
|
||||
return securityIgnoreUrls;
|
||||
}
|
||||
|
||||
public void setSecurityIgnoreUrls(List<String> securityIgnoreUrls) {
|
||||
this.securityIgnoreUrls = securityIgnoreUrls;
|
||||
}
|
||||
|
||||
public WxConfig getWx() {
|
||||
return wx;
|
||||
}
|
||||
|
||||
public void setWx(WxConfig wx) {
|
||||
this.wx = wx;
|
||||
}
|
||||
|
||||
public QnConfig getQn() {
|
||||
return qn;
|
||||
}
|
||||
|
||||
public void setQn(QnConfig qn) {
|
||||
this.qn = qn;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,47 @@
|
||||
package com.mindskip.xzs.configuration.property;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class WxConfig {
|
||||
|
||||
|
||||
private String appid;
|
||||
private String secret;
|
||||
private Duration tokenToLive;
|
||||
private List<String> securityIgnoreUrls;
|
||||
|
||||
public String getAppid() {
|
||||
return appid;
|
||||
}
|
||||
|
||||
public void setAppid(String appid) {
|
||||
this.appid = appid;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public Duration getTokenToLive() {
|
||||
return tokenToLive;
|
||||
}
|
||||
|
||||
public void setTokenToLive(Duration tokenToLive) {
|
||||
this.tokenToLive = tokenToLive;
|
||||
}
|
||||
|
||||
public List<String> getSecurityIgnoreUrls() {
|
||||
return securityIgnoreUrls;
|
||||
}
|
||||
|
||||
public void setSecurityIgnoreUrls(List<String> securityIgnoreUrls) {
|
||||
this.securityIgnoreUrls = securityIgnoreUrls;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,26 +29,6 @@ import java.time.Duration;
|
||||
@EnableCaching
|
||||
public class CacheConfig extends CachingConfigurerSupport {
|
||||
|
||||
/* @Autowired
|
||||
private CacheProperties cacheProperties;*/
|
||||
|
||||
/**
|
||||
* redis序列化修改为ObjectMapper
|
||||
*
|
||||
* @return RedisCacheConfiguration
|
||||
*/
|
||||
/* @Bean
|
||||
public RedisCacheConfiguration redisCacheConfiguration() {
|
||||
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
serializer.setObjectMapper(objectMapper);
|
||||
return RedisCacheConfiguration.defaultCacheConfig().entryTtl(cacheProperties.getRedis().getTimeToLive())
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
|
||||
}*/
|
||||
|
||||
|
||||
/**
|
||||
* spring boot redis默认序列化方式
|
||||
*
|
||||
|
@ -2,7 +2,7 @@ package com.mindskip.xzs.configuration.spring.mvc;
|
||||
|
||||
import com.mindskip.xzs.configuration.property.SystemConfig;
|
||||
import com.mindskip.xzs.configuration.spring.wx.TokenHandlerInterceptor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.*;
|
||||
|
||||
@ -10,16 +10,21 @@ import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
|
||||
|
||||
private final TokenHandlerInterceptor tokenHandlerInterceptor;
|
||||
private final SystemConfig systemConfig;
|
||||
|
||||
@Autowired
|
||||
public WebMvcConfiguration(TokenHandlerInterceptor tokenHandlerInterceptor, SystemConfig systemConfig) {
|
||||
this.tokenHandlerInterceptor = tokenHandlerInterceptor;
|
||||
this.systemConfig = systemConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addRedirectViewController("/", "/student/index.html");
|
||||
|
@ -1,14 +1,37 @@
|
||||
package com.mindskip.xzs.configuration.spring.security;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class AuthenticationBean {
|
||||
private String userName;
|
||||
private String password;
|
||||
private boolean remember;
|
||||
|
||||
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 boolean isRemember() {
|
||||
return remember;
|
||||
}
|
||||
|
||||
public void setRemember(boolean remember) {
|
||||
this.remember = remember;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 未登录
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
@Component
|
||||
public final class LoginAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
|
||||
|
@ -12,7 +12,7 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 账号验证异常
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
@Component
|
||||
public class RestAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||
|
@ -24,9 +24,8 @@ import java.util.ArrayList;
|
||||
/**
|
||||
* 登录用户名密码验证
|
||||
*
|
||||
* @author : Alvis
|
||||
* @author : 武汉思维跳跃科技有限公司
|
||||
* Description : 身份验证
|
||||
* Creation Date: 2018-05-02 5:00 PM
|
||||
*/
|
||||
|
||||
@Component
|
||||
|
@ -4,7 +4,7 @@ import com.mindskip.xzs.base.SystemCode;
|
||||
import com.mindskip.xzs.domain.UserEventLog;
|
||||
import com.mindskip.xzs.event.UserEvent;
|
||||
import com.mindskip.xzs.service.UserService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
@ -20,15 +20,20 @@ import java.util.Date;
|
||||
/**
|
||||
* 登录成功返回
|
||||
*
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class RestAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public RestAuthenticationSuccessHandler(ApplicationEventPublisher eventPublisher, UserService userService) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||
User springUser = (User) authentication.getPrincipal();
|
||||
|
@ -14,9 +14,8 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author : Alvis
|
||||
* @author : 武汉思维跳跃科技有限公司
|
||||
* Description : 验证通过之后,第二、三...请求,会调用此类
|
||||
* Creation Date: 2018-05-02 4:32 PM
|
||||
*/
|
||||
|
||||
@Component
|
||||
|
@ -19,7 +19,7 @@ import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 登录参数序列化
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
|
||||
public class RestLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
@ -5,7 +5,7 @@ import com.mindskip.xzs.domain.User;
|
||||
import com.mindskip.xzs.domain.UserEventLog;
|
||||
import com.mindskip.xzs.event.UserEvent;
|
||||
import com.mindskip.xzs.service.UserService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
@ -18,15 +18,20 @@ import java.util.Date;
|
||||
/**
|
||||
* 用户登出
|
||||
*
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class RestLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public RestLogoutSuccessHandler(ApplicationEventPublisher eventPublisher, UserService userService) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
||||
org.springframework.security.core.userdetails.User springUser = (org.springframework.security.core.userdetails.User) authentication.getPrincipal();
|
||||
|
@ -7,7 +7,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 记住我,Cookie
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
public class RestTokenBasedRememberMeServices extends TokenBasedRememberMeServices {
|
||||
public RestTokenBasedRememberMeServices(String key, UserDetailsService userDetailsService) {
|
||||
|
@ -10,7 +10,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
public class RestUtil {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RestUtil.class);
|
||||
|
@ -3,7 +3,7 @@ package com.mindskip.xzs.configuration.spring.security;
|
||||
import com.mindskip.xzs.configuration.property.CookieConfig;
|
||||
import com.mindskip.xzs.configuration.property.SystemConfig;
|
||||
import com.mindskip.xzs.domain.enums.RoleEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@ -19,7 +19,7 @@ import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author alvis
|
||||
* @author 武汉思维跳跃科技有限公司
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@ -27,7 +27,6 @@ import java.util.List;
|
||||
public class SecurityConfigurer {
|
||||
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final SystemConfig systemConfig;
|
||||
@ -39,6 +38,18 @@ public class SecurityConfigurer {
|
||||
private final RestLogoutSuccessHandler restLogoutSuccessHandler;
|
||||
private final RestAccessDeniedHandler restAccessDeniedHandler;
|
||||
|
||||
@Autowired
|
||||
public FormLoginWebSecurityConfigurerAdapter(SystemConfig systemConfig, LoginAuthenticationEntryPoint restAuthenticationEntryPoint, RestAuthenticationProvider restAuthenticationProvider, RestDetailsServiceImpl formDetailsService, RestAuthenticationSuccessHandler restAuthenticationSuccessHandler, RestAuthenticationFailureHandler restAuthenticationFailureHandler, RestLogoutSuccessHandler restLogoutSuccessHandler, RestAccessDeniedHandler restAccessDeniedHandler) {
|
||||
this.systemConfig = systemConfig;
|
||||
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
|
||||
this.restAuthenticationProvider = restAuthenticationProvider;
|
||||
this.formDetailsService = formDetailsService;
|
||||
this.restAuthenticationSuccessHandler = restAuthenticationSuccessHandler;
|
||||
this.restAuthenticationFailureHandler = restAuthenticationFailureHandler;
|
||||
this.restLogoutSuccessHandler = restLogoutSuccessHandler;
|
||||
this.restAccessDeniedHandler = restAccessDeniedHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param http http
|
||||
* @throws Exception exception
|
||||
@ -57,6 +68,8 @@ public class SecurityConfigurer {
|
||||
.authorizeRequests()
|
||||
.antMatchers(securityIgnoreUrls.toArray(ignores)).permitAll()
|
||||
.antMatchers("/api/admin/**").hasRole(RoleEnum.ADMIN.getName())
|
||||
.antMatchers("/api/student/exampaper/answer/read/*").hasAnyRole(RoleEnum.ADMIN.getName(),RoleEnum.STUDENT.getName())
|
||||
.antMatchers("/api/student/exampaper/answer/edit").hasAnyRole(RoleEnum.ADMIN.getName())
|
||||
.antMatchers("/api/student/**").hasRole(RoleEnum.STUDENT.getName())
|
||||
.anyRequest().permitAll()
|
||||
.and().exceptionHandling().accessDeniedHandler(restAccessDeniedHandler)
|
||||
|
@ -2,18 +2,22 @@ package com.mindskip.xzs.context;
|
||||
|
||||
import com.mindskip.xzs.domain.User;
|
||||
import com.mindskip.xzs.service.UserService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class WebContext {
|
||||
private static final String USER_ATTRIBUTES = "USER_ATTRIBUTES";
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public WebContext(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
|
||||
public void setCurrentUser(User user) {
|
||||
RequestContextHolder.currentRequestAttributes().setAttribute(USER_ATTRIBUTES, user, RequestAttributes.SCOPE_REQUEST);
|
||||
|
@ -5,8 +5,7 @@ import com.mindskip.xzs.base.RestResponse;
|
||||
import com.mindskip.xzs.service.*;
|
||||
import com.mindskip.xzs.utility.DateTimeUtil;
|
||||
import com.mindskip.xzs.viewmodel.admin.dashboard.IndexVM;
|
||||
import com.mindskip.xzs.service.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -15,16 +14,23 @@ import java.util.List;
|
||||
|
||||
@RestController("AdminDashboardController")
|
||||
@RequestMapping(value = "/api/admin/dashboard")
|
||||
@AllArgsConstructor
|
||||
public class DashboardController extends BaseApiController {
|
||||
|
||||
|
||||
private final ExamPaperService examPaperService;
|
||||
private final QuestionService questionService;
|
||||
private final ExamPaperAnswerService examPaperAnswerService;
|
||||
private final ExamPaperQuestionCustomerAnswerService examPaperQuestionCustomerAnswerService;
|
||||
private final UserEventLogService userEventLogService;
|
||||
|
||||
@Autowired
|
||||
public DashboardController(ExamPaperService examPaperService, QuestionService questionService, ExamPaperAnswerService examPaperAnswerService, ExamPaperQuestionCustomerAnswerService examPaperQuestionCustomerAnswerService, UserEventLogService userEventLogService) {
|
||||
this.examPaperService = examPaperService;
|
||||
this.questionService = questionService;
|
||||
this.examPaperAnswerService = examPaperAnswerService;
|
||||
this.examPaperQuestionCustomerAnswerService = examPaperQuestionCustomerAnswerService;
|
||||
this.userEventLogService = userEventLogService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/index", method = RequestMethod.POST)
|
||||
public RestResponse<IndexVM> Index() {
|
||||
IndexVM vm = new IndexVM();
|
||||
|
@ -10,7 +10,7 @@ import com.mindskip.xzs.viewmodel.admin.education.SubjectEditRequestVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.education.SubjectPageRequestVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.education.SubjectResponseVM;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
@ -18,11 +18,15 @@ import java.util.List;
|
||||
|
||||
@RestController("AdminEducationController")
|
||||
@RequestMapping(value = "/api/admin/education")
|
||||
@AllArgsConstructor
|
||||
public class EducationController extends BaseApiController {
|
||||
|
||||
private final SubjectService subjectService;
|
||||
|
||||
@Autowired
|
||||
public EducationController(SubjectService subjectService) {
|
||||
this.subjectService = subjectService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/subject/list", method = RequestMethod.POST)
|
||||
public RestResponse<List<Subject>> list() {
|
||||
List<Subject> subjects = subjectService.allSubject();
|
||||
|
@ -0,0 +1,54 @@
|
||||
package com.mindskip.xzs.controller.admin;
|
||||
|
||||
import com.mindskip.xzs.base.BaseApiController;
|
||||
import com.mindskip.xzs.base.RestResponse;
|
||||
import com.mindskip.xzs.domain.ExamPaperAnswer;
|
||||
import com.mindskip.xzs.domain.Subject;
|
||||
import com.mindskip.xzs.domain.User;
|
||||
import com.mindskip.xzs.service.*;
|
||||
import com.mindskip.xzs.utility.DateTimeUtil;
|
||||
import com.mindskip.xzs.utility.ExamUtil;
|
||||
import com.mindskip.xzs.utility.PageInfoHelper;
|
||||
import com.mindskip.xzs.viewmodel.student.exampaper.ExamPaperAnswerPageResponseVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.paper.ExamPaperAnswerPageRequestVM;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController("AdminExamPaperAnswerController")
|
||||
@RequestMapping(value = "/api/admin/examPaperAnswer")
|
||||
public class ExamPaperAnswerController extends BaseApiController {
|
||||
|
||||
private final ExamPaperAnswerService examPaperAnswerService;
|
||||
private final SubjectService subjectService;
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public ExamPaperAnswerController(ExamPaperAnswerService examPaperAnswerService, SubjectService subjectService, UserService userService) {
|
||||
this.examPaperAnswerService = examPaperAnswerService;
|
||||
this.subjectService = subjectService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/page", method = RequestMethod.POST)
|
||||
public RestResponse<PageInfo<ExamPaperAnswerPageResponseVM>> pageJudgeList(@RequestBody ExamPaperAnswerPageRequestVM model) {
|
||||
PageInfo<ExamPaperAnswer> pageInfo = examPaperAnswerService.adminPage(model);
|
||||
PageInfo<ExamPaperAnswerPageResponseVM> page = PageInfoHelper.copyMap(pageInfo, e -> {
|
||||
ExamPaperAnswerPageResponseVM vm = modelMapper.map(e, ExamPaperAnswerPageResponseVM.class);
|
||||
Subject subject = subjectService.selectById(vm.getSubjectId());
|
||||
vm.setDoTime(ExamUtil.secondToVM(e.getDoTime()));
|
||||
vm.setSystemScore(ExamUtil.scoreToVM(e.getSystemScore()));
|
||||
vm.setUserScore(ExamUtil.scoreToVM(e.getUserScore()));
|
||||
vm.setPaperScore(ExamUtil.scoreToVM(e.getPaperScore()));
|
||||
vm.setSubjectName(subject.getName());
|
||||
vm.setCreateTime(DateTimeUtil.dateFormat(e.getCreateTime()));
|
||||
User user = userService.selectById(e.getCreateUser());
|
||||
vm.setUserName(user.getRealName());
|
||||
return vm;
|
||||
});
|
||||
return RestResponse.ok(page);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -10,18 +10,22 @@ import com.mindskip.xzs.viewmodel.admin.exam.ExamPaperPageRequestVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.exam.ExamPaperEditRequestVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.exam.ExamResponseVM;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@RestController("AdminExamPaperController")
|
||||
@RequestMapping(value = "/api/admin/exam/paper")
|
||||
@AllArgsConstructor
|
||||
public class ExamPaperController extends BaseApiController {
|
||||
|
||||
private final ExamPaperService examPaperService;
|
||||
|
||||
@Autowired
|
||||
public ExamPaperController(ExamPaperService examPaperService) {
|
||||
this.examPaperService = examPaperService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/page", method = RequestMethod.POST)
|
||||
public RestResponse<PageInfo<ExamResponseVM>> pageList(@RequestBody ExamPaperPageRequestVM model) {
|
||||
PageInfo<ExamPaper> pageInfo = examPaperService.page(model);
|
||||
|
@ -14,7 +14,7 @@ import com.mindskip.xzs.viewmodel.admin.message.MessagePageRequestVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.message.MessageResponseVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.message.MessageSendVM;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@ -27,12 +27,17 @@ import java.util.stream.Collectors;
|
||||
|
||||
@RestController("AdminMessageController")
|
||||
@RequestMapping(value = "/api/admin/message")
|
||||
@AllArgsConstructor
|
||||
public class MessageController extends BaseApiController {
|
||||
|
||||
private final MessageService messageService;
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public MessageController(MessageService messageService, UserService userService) {
|
||||
this.messageService = messageService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/page", method = RequestMethod.POST)
|
||||
public RestResponse<PageInfo<MessageResponseVM>> pageList(@RequestBody MessagePageRequestVM model) {
|
||||
PageInfo<Message> pageInfo = messageService.page(model);
|
||||
|
@ -14,21 +14,25 @@ import com.mindskip.xzs.viewmodel.admin.question.QuestionEditRequestVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.question.QuestionPageRequestVM;
|
||||
import com.mindskip.xzs.viewmodel.admin.question.QuestionResponseVM;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.mindskip.xzs.utility.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@RestController("AdminQuestionController")
|
||||
@RequestMapping(value = "/api/admin/question")
|
||||
@AllArgsConstructor
|
||||
public class QuestionController extends BaseApiController {
|
||||
|
||||
private final QuestionService questionService;
|
||||
private final TextContentService textContentService;
|
||||
|
||||
@Autowired
|
||||
public QuestionController(QuestionService questionService, TextContentService textContentService) {
|
||||
this.questionService = questionService;
|
||||
this.textContentService = textContentService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/page", method = RequestMethod.POST)
|
||||
public RestResponse<PageInfo<QuestionResponseVM>> pageList(@RequestBody QuestionPageRequestVM model) {
|
||||
PageInfo<Question> pageInfo = questionService.page(model);
|
||||
|