Commit b769660cd6986ed5d519128a4db3ba2f3445f401

Authored by 梁保满
1 parent 13b58a42

备课组题细节调整,随堂问列表页面开发完成

1 -[ //测试用,后续后端获取  
2 - {  
3 - path: "/examinationPaper",  
4 - iconCls: "fa fa-file-text", // 图标样式class  
5 - name: "备题组卷",  
6 - component: Layout,  
7 - alone: true,  
8 - children: [  
9 - {  
10 - path: "/examinationPaper",  
11 - iconCls: "fa fa-file-text", // 图标样式class  
12 - name: "",  
13 - component: ExaminationPaper,  
14 - children: []  
15 - },  
16 - {  
17 - path: "/examinationPaperAdd",  
18 - iconCls: "", // 图标样式class  
19 - name: "添加答题卡",  
20 - component: ExaminationPaperAdd,  
21 - children: []  
22 - },  
23 - {  
24 - path: "/examinationPaperEdit",  
25 - iconCls: "", // 图标样式class  
26 - name: "修改答题卡",  
27 - component: ExaminationPaperEdit,  
28 - children: []  
29 - },  
30 - {  
31 - path: "/examinationPaperRecycle",  
32 - iconCls: "", // 图标样式class  
33 - name: "已归档答题卡",  
34 - component: ExaminationPaperRecycle,  
35 - children: []  
36 - },  
37 - ]  
38 - },  
39 - {  
40 - path: "/ask",  
41 - iconCls: "fa fa-bar-chart", // 图标样式class  
42 - name: "随堂问报表",  
43 - component: Layout,  
44 - alone: true,  
45 - children: [  
46 - {  
47 - path: "/ask",  
48 - iconCls: "fa fa-bar-chart", // 图标样式class  
49 - name: "",  
50 - component: Ask,  
51 - children: []  
52 -  
53 - },  
54 - {  
55 - path: "/askAnalysis",  
56 - iconCls: "", // 图标样式class  
57 - name: "随堂问报表分析",  
58 - component: AskAnalysis,  
59 - children: []  
60 - }  
61 - ]  
62 - },  
63 - {  
64 - path: "/test",  
65 - iconCls: "fa fa-pie-chart", // 图标样式class  
66 - name: "即时测报表",  
67 - component: Layout,  
68 - alone: true,  
69 - children: [  
70 - {  
71 - path: "/test",  
72 - iconCls: "fa fa-pie-chart", // 图标样式class  
73 - name: "",  
74 - component: Test,  
75 - children: []  
76 - },  
77 - {  
78 - path: "/testAnalysis",  
79 - iconCls: "", // 图标样式class  
80 - name: "即时测报表分析",  
81 - component: TestAnalysis,  
82 - children: []  
83 - }  
84 -  
85 - ]  
86 - },  
87 - {  
88 - path: "/portrait",  
89 - iconCls: "fa fa-users", // 图标样式class  
90 - name: "学生画像",  
91 - component: Layout,  
92 - alone: true,  
93 - children: [  
94 - {  
95 - path: "/portrait",  
96 - iconCls: "fa fa-users", // 图标样式class  
97 - name: "",  
98 - component: Portrait,  
99 - children: []  
100 - }  
101 - ]  
102 - },  
103 -  
104 - {  
105 - path: "/setUpConglomerate",  
106 - iconCls: "fa fa-building", // 图标样式class  
107 - name: "学校管理",  
108 - component: Layout,  
109 - alone: true,  
110 - children: [  
111 - {  
112 - path: "/setUpConglomerate",  
113 - iconCls: "fa fa-building",  
114 - name: '集团管理',  
115 - component: SetUpConglomerate,  
116 - children: []  
117 - },  
118 - ]  
119 - },  
120 - {  
121 - path: "/setUpAccount",  
122 - iconCls: "fa fa-id-card-o", // 图标样式class  
123 - name: "账号管理",  
124 - component: Layout,  
125 - alone: true,  
126 - children: [  
127 - {  
128 - path: "/setUpAccount",  
129 - iconCls: "fa fa-id-card-o",  
130 - name: '',  
131 - component: SetUpAccount,  
132 - children: []  
133 - },  
134 - ]  
135 - },  
136 - {  
137 - path: "/",  
138 - iconCls: "fa fa-cog",  
139 - name: '学校设置',  
140 - component: Layout,  
141 - children: [  
142 - {  
143 - path: "/setUpSchool",  
144 - iconCls: "fa fa-calculator",  
145 - name: '学校设置',  
146 - component: SetUpSchool,  
147 - children: []  
148 - },  
149 - {  
150 - path: "/setUpTeacher",  
151 - iconCls: "fa fa-male",  
152 - name: '教师管理',  
153 - component: SetUpTeacher,  
154 - children: []  
155 - },  
156 - {  
157 - path: "/setUpStudent",  
158 - iconCls: "fa fa-mortar-board",  
159 - name: '学生管理',  
160 - component: SetUpStudent,  
161 - children: []  
162 - },  
163 - ]  
164 - },  
165 - {  
166 - path: "/card",  
167 - iconCls: "fa fa-id-card", // 图标样式class  
168 - name: "发卡记录",  
169 - component: Layout,  
170 - alone: true,  
171 - children: [  
172 - {  
173 - path: "/card",  
174 - iconCls: "fa fa-id-card", // 图标样式class  
175 - name: "",  
176 - component: Card,  
177 - children: []  
178 - }  
179 - ]  
180 - },  
181 - {  
182 - path: "/device",  
183 - iconCls: "fa fa-dashboard", // 图标样式class  
184 - name: "设备状态",  
185 - component: Layout,  
186 - alone: true,  
187 - children: [  
188 - {  
189 - path: "/device",  
190 - iconCls: "fa fa-dashboard", // 图标样式class  
191 - name: "",  
192 - component: Device,  
193 - children: []  
194 - }  
195 - ]  
196 - },  
197 - {  
198 - path: "/analysis",  
199 - iconCls: "fa fa-area-chart", // 图标样式class  
200 - name: "使用分析",  
201 - component: Layout,  
202 - alone: true,  
203 - children: [  
204 - {  
205 - path: "/analysis",  
206 - iconCls: "fa fa-area-chart", // 图标样式class  
207 - name: "",  
208 - component: Analysis,  
209 - children: []  
210 - }  
211 - ]  
212 - },  
213 - {  
214 - path: "/down",  
215 - iconCls: "fa fa-download", // 图标样式class  
216 - name: "软件下载",  
217 - component: Layout,  
218 - alone: true,  
219 - children: [  
220 - {  
221 - path: "/down",  
222 - iconCls: "fa fa-download", // 图标样式class  
223 - name: "发卡软件",  
224 - component: Down,  
225 - children: []  
226 - },  
227 - {  
228 - path: "/downClient",  
229 - iconCls: "", // 图标样式class  
230 - name: "授课端软件",  
231 - component: DownClient,  
232 - children: []  
233 - }  
234 - ]  
235 - },  
236 - {  
237 - path: "/dataSync",  
238 - iconCls: "fa fa-random", // 图标样式class  
239 - name: "数据同步",  
240 - component: Layout,  
241 - alone: true,  
242 - children: [  
243 - {  
244 - path: "/dataSync",  
245 - iconCls: "fa fa-random", // 图标样式class  
246 - name: "",  
247 - component: DataSync,  
248 - children: []  
249 - }  
250 - ]  
251 - },  
252 - {  
253 - path: "*",  
254 - redirect: "/404",  
255 - hidden: true,  
256 - children: []  
257 - } 1 +[
  2 + "examinationPaper",
  3 + "examinationPaperAdd",
  4 + "examinationPaperEdit",
  5 + "examinationPaperRecycle",
  6 + "ask",
  7 + "askAnalysis",
  8 + "test",
  9 + "testAnalysis",
  10 + "portrait",
  11 + "setUpConglomerate",
  12 + "setUpAccount",
  13 + "setUpSchool",
  14 + "setUpTeacher",
  15 + "setUpStudent",
  16 + "card",
  17 + "device",
  18 + "analysis",
  19 + "down",
  20 + "downClient",
  21 + "dataSync"
258 ] 22 ]
259 \ No newline at end of file 23 \ No newline at end of file
src/api/apis/answerSheet.js
1 1
2 -import axios from "../axios" 2 +import service from "../axios"
3 import answerSheet from "../urls/answerSheet" 3 import answerSheet from "../urls/answerSheet"
4 4
5 export default { 5 export default {
6 // 答题卡列表 6 // 答题卡列表
7 fetchAnswerList(data) { 7 fetchAnswerList(data) {
8 - return axios({ 8 + return service({
9 url: answerSheet.answerList, 9 url: answerSheet.answerList,
10 method: 'POST', 10 method: 'POST',
11 data 11 data
@@ -13,7 +13,7 @@ export default { @@ -13,7 +13,7 @@ export default {
13 }, 13 },
14 // 测验类型 14 // 测验类型
15 fetchTypeNames(data) { 15 fetchTypeNames(data) {
16 - return axios({ 16 + return service({
17 url: answerSheet.typeNames, 17 url: answerSheet.typeNames,
18 method: 'POST', 18 method: 'POST',
19 data 19 data
@@ -21,7 +21,7 @@ export default { @@ -21,7 +21,7 @@ export default {
21 }, 21 },
22 // 班级列表 22 // 班级列表
23 fetchClassList(data) { 23 fetchClassList(data) {
24 - return axios({ 24 + return service({
25 url: answerSheet.classList, 25 url: answerSheet.classList,
26 method: 'POST', 26 method: 'POST',
27 data 27 data
@@ -29,7 +29,7 @@ export default { @@ -29,7 +29,7 @@ export default {
29 }, 29 },
30 // 科目列表 30 // 科目列表
31 fetchSubjectList(data) { 31 fetchSubjectList(data) {
32 - return axios({ 32 + return service({
33 url: answerSheet.subjectList, 33 url: answerSheet.subjectList,
34 method: 'POST', 34 method: 'POST',
35 data 35 data
@@ -37,7 +37,7 @@ export default { @@ -37,7 +37,7 @@ export default {
37 }, 37 },
38 // 年级列表 38 // 年级列表
39 fetchGradeList(data) { 39 fetchGradeList(data) {
40 - return axios({ 40 + return service({
41 url: answerSheet.gradeList, 41 url: answerSheet.gradeList,
42 method: 'POST', 42 method: 'POST',
43 data 43 data
@@ -45,7 +45,7 @@ export default { @@ -45,7 +45,7 @@ export default {
45 }, 45 },
46 // 添加测验类型 46 // 添加测验类型
47 addAnswerTypeName(data) { 47 addAnswerTypeName(data) {
48 - return axios({ 48 + return service({
49 url: answerSheet.addAnswerTypeName, 49 url: answerSheet.addAnswerTypeName,
50 method: 'POST', 50 method: 'POST',
51 data 51 data
@@ -53,7 +53,7 @@ export default { @@ -53,7 +53,7 @@ export default {
53 }, 53 },
54 // 保存答题卡 54 // 保存答题卡
55 saveAnswerSheet(data) { 55 saveAnswerSheet(data) {
56 - return axios({ 56 + return service({
57 url: answerSheet.saveAnswerSheet, 57 url: answerSheet.saveAnswerSheet,
58 method: 'POST', 58 method: 'POST',
59 data 59 data
@@ -61,7 +61,7 @@ export default { @@ -61,7 +61,7 @@ export default {
61 }, 61 },
62 // 删除答题卡 62 // 删除答题卡
63 removeAnswerSheet(data) { 63 removeAnswerSheet(data) {
64 - return axios({ 64 + return service({
65 url: answerSheet.removeAnswerSheet, 65 url: answerSheet.removeAnswerSheet,
66 method: 'POST', 66 method: 'POST',
67 data 67 data
@@ -69,7 +69,7 @@ export default { @@ -69,7 +69,7 @@ export default {
69 }, 69 },
70 // 恢复答题卡 70 // 恢复答题卡
71 useAnswerSheet(data) { 71 useAnswerSheet(data) {
72 - return axios({ 72 + return service({
73 url: answerSheet.useAnswerSheet, 73 url: answerSheet.useAnswerSheet,
74 method: 'POST', 74 method: 'POST',
75 data 75 data
@@ -77,7 +77,7 @@ export default { @@ -77,7 +77,7 @@ export default {
77 }, 77 },
78 // 恢复答题卡 78 // 恢复答题卡
79 updateAnswerSheet(data) { 79 updateAnswerSheet(data) {
80 - return axios({ 80 + return service({
81 url: answerSheet.updateAnswerSheet, 81 url: answerSheet.updateAnswerSheet,
82 method: 'POST', 82 method: 'POST',
83 data 83 data
src/api/apis/ask.js 0 → 100644
  1 +
  2 +import service from "../axios"
  3 +import askUrls from "../urls/login"
  4 +
  5 +export default {
  6 + // 账号密码登陆
  7 + fetchQuizList(data) {
  8 + return service({
  9 + url: askUrls.quizList,
  10 + method: 'POST',
  11 + data
  12 + })
  13 + },
  14 +}
src/api/apis/login.js
1 1
2 -import axios from "../axios" 2 +import service from "../axios"
3 import loginUrls from "../urls/login" 3 import loginUrls from "../urls/login"
4 4
5 export default { 5 export default {
6 // 账号密码登陆 6 // 账号密码登陆
7 fetchLogin(data) { 7 fetchLogin(data) {
8 - return axios({ 8 + return service({
9 url: loginUrls.login, 9 url: loginUrls.login,
10 method: 'POST', 10 method: 'POST',
11 data 11 data
src/api/apis/role.js
1 1
2 -import axios from "../axios" 2 +import service from "../axios"
3 import roleUrls from "../urls/role" 3 import roleUrls from "../urls/role"
4 4
5 export default { 5 export default {
6 // 获取权限列表 6 // 获取权限列表
7 fetchGetRoleList () { 7 fetchGetRoleList () {
8 - return axios.post(roleUrls.getRoleList) 8 + return service.post(roleUrls.getRoleList)
9 }, 9 },
10 } 10 }
11 11
src/api/axios.js
@@ -6,11 +6,13 @@ import router from "@/router/index" @@ -6,11 +6,13 @@ import router from "@/router/index"
6 import store from "@/store" 6 import store from "@/store"
7 import conf from "../config/index"; // 路径配置 7 import conf from "../config/index"; // 路径配置
8 // axios默认配置 8 // axios默认配置
9 -axios.defaults.timeout = 1000000000 // 超时时间  
10 -axios.defaults.baseURL = conf.baseURL  
11 - 9 +const service = axios.create({
  10 + baseURL: conf.baseURL, // api的base_url
  11 + timeout: 600000000000000, // 请求超时时间
  12 + withCredentials: true,
  13 +});
12 // http request 拦截器 14 // http request 拦截器
13 -axios.interceptors.request.use(config => { 15 +service.interceptors.request.use(config => {
14 NProgress.start() 16 NProgress.start()
15 config.headers["Content-Type"] = "application/json;charset=UTF-8" 17 config.headers["Content-Type"] = "application/json;charset=UTF-8"
16 18
@@ -27,16 +29,16 @@ axios.interceptors.request.use(config => { @@ -27,16 +29,16 @@ axios.interceptors.request.use(config => {
27 }) 29 })
28 30
29 // http response 拦截器 31 // http response 拦截器
30 -axios.interceptors.response.use( 32 +service.interceptors.response.use(
31 response => { 33 response => {
32 - const res = respones.data; 34 + const res = response.data;
33 NProgress.done() 35 NProgress.done()
34 - if (respones.config.cancelToken) {  
35 - store.commit('delTokenSources', respones.config.cancelToken) 36 + if (response.config.cancelToken) {
  37 + store.commit('delTokenSources', response.config.cancelToken)
36 } 38 }
37 - if (respones.status == 200) { 39 + if (response.status == 200) {
38 Cookies.set("access_token", response.data.message, { expires: 1 / 12 }) 40 Cookies.set("access_token", response.data.message, { expires: 1 / 12 })
39 - // console.log(respones.status) 41 + // console.log(response.status)
40 if (res.code == 999) { 42 if (res.code == 999) {
41 if (!location.href.includes('localhost')) { 43 if (!location.href.includes('localhost')) {
42 if (res.data) { 44 if (res.data) {
@@ -88,4 +90,4 @@ axios.interceptors.response.use( @@ -88,4 +90,4 @@ axios.interceptors.response.use(
88 } 90 }
89 return Promise.reject(error.response) // 返回接口返回的错误信息 91 return Promise.reject(error.response) // 返回接口返回的错误信息
90 }) 92 })
91 -export default axios 93 +export default service
src/api/urls/ask.js 0 → 100644
  1 +
  2 +export default {
  3 + // 账号密码登陆
  4 + quizList: "/web/quizList",
  5 +}
src/api/urls/login.js
1 1
2 export default { 2 export default {
3 // 账号密码登陆 3 // 账号密码登陆
4 - login: "/admin/user/login" 4 + login: "/web/login",
  5 + ssoLogin: "/sso/login"
5 } 6 }
src/assets/css/index.scss
@@ -3,65 +3,113 @@ @@ -3,65 +3,113 @@
3 display: flex; 3 display: flex;
4 justify-content: space-between; 4 justify-content: space-between;
5 align-items: center; 5 align-items: center;
  6 +
6 .btn-box { 7 .btn-box {
7 display: flex; 8 display: flex;
8 } 9 }
  10 +
9 .sel-box { 11 .sel-box {
10 - display: flex;  
11 - align-items: center;  
12 - flex-wrap: nowrap;  
13 - .sel {  
14 - width: 8%;  
15 - min-width: 90px;  
16 - margin-right: 20px;  
17 - }  
18 - .el-input__inner{  
19 - border-radius: 20px;  
20 - border: 1px solid #e2e2e2;  
21 - height: 36px;  
22 - line-height: 34px;  
23 - }  
24 - .el-input__icon {  
25 - line-height: 34px;  
26 - }  
27 - .el-date-editor.el-input,  
28 - .el-date-editor.el-input__inner {  
29 - width: 200px;  
30 - }  
31 - .input-with-select {  
32 - width: 200px;  
33 - height: 36px;  
34 - margin-right: 50px;  
35 - border-radius: 20px;  
36 - border: 1px solid #e2e2e2;  
37 - box-sizing: border-box; 12 + display: flex;
  13 + align-items: center;
  14 + flex-wrap: nowrap;
  15 +
  16 + .sel {
  17 + width: 8%;
  18 + min-width: 160px;
  19 + margin-right: 20px;
  20 + }
  21 +
38 .el-input__inner { 22 .el-input__inner {
39 border-radius: 20px; 23 border-radius: 20px;
40 - border: none;  
41 - height: 34px; 24 + border: 1px solid #e2e2e2;
  25 + height: 36px;
42 line-height: 34px; 26 line-height: 34px;
43 } 27 }
44 - .el-input-group__append, .el-input-group__prepend {  
45 - border: none;  
46 - background: transparent; 28 +
  29 + .el-input__icon {
  30 + line-height: 34px;
47 } 31 }
48 - }  
49 - .d1 {  
50 - margin-left: 30px;  
51 - }  
52 - .p1 {  
53 - flex: 1;  
54 - .s1 {  
55 - margin-left: 36px;  
56 - cursor: pointer;  
57 - color: #7f7f7f;  
58 - &:hover {  
59 - color: #409eff; 32 +
  33 + .el-date-editor.el-input,
  34 + .el-date-editor.el-input__inner {
  35 + width: 160px;
  36 + }
  37 +
  38 + .input-with-select {
  39 + width: 200px;
  40 + height: 36px;
  41 + margin-right: 50px;
  42 + border-radius: 20px;
  43 + border: 1px solid #e2e2e2;
  44 + box-sizing: border-box;
  45 +
  46 + .el-input__inner {
  47 + border-radius: 20px;
  48 + border: none;
  49 + height: 34px;
  50 + line-height: 34px;
60 } 51 }
61 - &.active {  
62 - color: #667ffd; 52 +
  53 + .el-input-group__append,
  54 + .el-input-group__prepend {
  55 + border: none;
  56 + background: transparent;
63 } 57 }
64 } 58 }
  59 +
  60 + .p1 {
  61 + flex: 1;
  62 +
  63 + .s1 {
  64 + margin-left: 36px;
  65 + cursor: pointer;
  66 + color: #7f7f7f;
  67 +
  68 + &:hover {
  69 + color: #409eff;
  70 + }
  71 +
  72 + &.active {
  73 + color: #667ffd;
  74 + }
  75 + }
  76 + }
  77 + }
  78 +}
  79 +.answer-box {
  80 + .answer-s {
  81 + display: inline-block;
  82 + width: 30px;
  83 + height: 30px;
  84 + border: 1px solid #e2e2e2;
  85 + border-radius: 3px;
  86 + margin: 0 6px;
  87 + font-size: 16px;
  88 + color: #333;
  89 + text-align: center;
  90 + line-height: 30px;
  91 + &.active {
  92 + background: #5e78fa;
  93 + border-color: #5e78fa;
  94 + color: #fff;
  95 + }
65 } 96 }
66 } 97 }
  98 +.el-menu-item i {
  99 + width: 12px;
  100 + text-align: center;
  101 + margin-right: 8px;
  102 +}
  103 +
  104 +.el-table thead th.el-table__cell {
  105 + background: #f5f7fa;
  106 +}
  107 +
  108 +.el-menu--popup {
  109 + min-width: 160px;
  110 +}
  111 +.ellipsis {
  112 + overflow: hidden;
  113 + text-overflow: ellipsis;
  114 + white-space: nowrap;
67 } 115 }
68 \ No newline at end of file 116 \ No newline at end of file
src/assets/images/arrow.png 0 → 100644

470 Bytes

src/assets/nav/dataSync.png 0 → 100644

7.45 KB

src/main.js
@@ -14,8 +14,8 @@ import '@/components/globalComponents.js' @@ -14,8 +14,8 @@ import '@/components/globalComponents.js'
14 14
15 15
16 import "nprogress/nprogress.css" 16 import "nprogress/nprogress.css"
17 -import "element-ui/lib/theme-chalk/index.css"  
18 import "font-awesome/css/font-awesome.css" 17 import "font-awesome/css/font-awesome.css"
  18 +import "element-ui/lib/theme-chalk/index.css"
19 import "@/router/permission" 19 import "@/router/permission"
20 import "@/assets/css/base.css" 20 import "@/assets/css/base.css"
21 import "@/assets/css/index.scss" 21 import "@/assets/css/index.scss"
src/router/index.js
@@ -327,12 +327,6 @@ let addrouters = [ //测试用,后续后端获取 @@ -327,12 +327,6 @@ let addrouters = [ //测试用,后续后端获取
327 } 327 }
328 ] 328 ]
329 }, 329 },
330 - {  
331 - path: "*",  
332 - redirect: "/404",  
333 - hidden: true,  
334 - children: []  
335 - }  
336 ] 330 ]
337 331
338 export default new Router({ 332 export default new Router({
src/router/permission.js
1 import NProgress from "nprogress" 1 import NProgress from "nprogress"
2 import router from "./index" 2 import router from "./index"
3 import store from "../store" 3 import store from "../store"
4 -import {addrouters} from "./index"  
5 4
6 // 获取角色信息,根据用户权限动态加载路由 5 // 获取角色信息,根据用户权限动态加载路由
7 router.beforeEach((to, from, next) => { 6 router.beforeEach((to, from, next) => {
8 NProgress.start() 7 NProgress.start()
9 if (store.getters.token) { 8 if (store.getters.token) {
10 - if (to.path === "/login") {  
11 - next()  
12 - } else {  
13 - if (!store.getters.info.permissions) {  
14 - !(async function getAddRouters() {  
15 - // 省略 axios 请求代码 通过 token 向后台请求用户权限等信息,这里用假数据赋值  
16 - await store.commit("setInfo", {  
17 - permissions: [  
18 - {  
19 - role: "superAdmin",  
20 - roleName: "超级管理员"  
21 - }  
22 - ],  
23 - name: "李老师",  
24 - // avatar: data.avatar ? data.avatar : "",  
25 - // uid: data.id,  
26 - // authorityRouter:[], 9 + // if (to.path === "/login") {
  10 + next()
  11 + // } else {
  12 + // if (!store.getters.info.permissions) {
  13 + // (async function getAddRouters() {
  14 + // // 省略 axios 请求代码 通过 token 向后台请求用户权限等信息,这里用假数据赋值
  15 + // const userInfo = {
  16 + // permissions: [
  17 + // {
  18 + // role: "superAdmin",
  19 + // roleName: "超级管理员"
  20 + // }
  21 + // ],
  22 + // name: "李老师",
  23 + // // avatar: data.avatar ? data.avatar : "",
  24 + // // uid: data.id,
  25 + // authorityRouter: ["examinationPaper",
  26 + // "examinationPaperAdd",
  27 + // "examinationPaperEdit",
  28 + // "examinationPaperRecycle", "ask",
  29 + // "askAnalysis",
  30 + // "test",
  31 + // "testAnalysis", "portrait"],
27 32
28 - })  
29 - await store.commit("setRouters", addrouters)  
30 - let newAddRouters = store.getters.addRouters  
31 - newAddRouters.forEach(res => {  
32 - router.addRoute(res)  
33 - })  
34 - next({path: to.fullPath})  
35 - }())  
36 - } else { 33 + // }
  34 + // await store.commit("setInfo", { ...userInfo })
  35 + // await store.commit("setRouters", userInfo.authorityRouter)
  36 + // let newAddRouters = store.getters.addRouters
  37 + // newAddRouters.forEach(res => {
  38 + // router.addRoute(res)
  39 + // })
  40 + // router.addRoute({
  41 + // path: "*",
  42 + // redirect: "/404",
  43 + // hidden: true,
  44 + // children: []
  45 + // })
  46 + // next({ path: to.fullPath })
  47 + // }())
  48 + // } else {
  49 + // next()
  50 + // }
  51 + // }
  52 + } else {
  53 + if (store.getters.info && store.getters.addRouters) {
  54 + console.log(store.getters.addRouters)
  55 + store.commit("setToken", "isLogin");
  56 + store.commit(
  57 + "setRouters",
  58 + store.getters.info.authorityRouter
  59 + );
  60 +
  61 + let newAddRouters = store.getters.addRouters;
  62 + newAddRouters.forEach((res) => {
  63 + router.addRoute(res);
  64 + });
  65 + router.addRoute({
  66 + path: "*",
  67 + redirect: "/404",
  68 + hidden: true,
  69 + children: [],
  70 + });
  71 + next({ path: to.fullPath })
  72 + } else {
  73 + if (store.getters.code) {
37 next() 74 next()
  75 + } else {
  76 + if (to.path === "/login") {
  77 + next()
  78 + } else {
  79 + next({ path: "/login" })
  80 + }
38 } 81 }
39 } 82 }
40 - } else {  
41 - if (to.path === "/login") {  
42 - next()  
43 - }  
44 - next({ path: "/login" })  
45 -  
46 } 83 }
47 }) 84 })
48 85
49 router.afterEach(() => { 86 router.afterEach(() => {
50 NProgress.done() 87 NProgress.done()
51 }) 88 })
  89 +router.onError((error) => {
  90 + const pattern = /Loading chunk (\d)+ failed/g;
  91 + const isChunkLoadFailed = error.message.match(pattern);
  92 + const targetPath = router.history.pending.fullPath;
  93 + if (isChunkLoadFailed) { router.replace(targetPath); }
  94 +});
  95 +
52 96
53 97
54 // // 真实使用 98 // // 真实使用
src/store/index.js
@@ -4,25 +4,28 @@ import Cookies from "js-cookie" @@ -4,25 +4,28 @@ import Cookies from "js-cookie"
4 import layoutStore from "./modules/layout/index" 4 import layoutStore from "./modules/layout/index"
5 import { defaultRouter } from "@/router/index" 5 import { defaultRouter } from "@/router/index"
6 import { encryptLoginPassword } from "@/utils"; 6 import { encryptLoginPassword } from "@/utils";
7 -import { b64DecodeUnicode } from "@/utils";  
8 7
9 import request from "@/api/index" 8 import request from "@/api/index"
10 import router from "@/router/index" 9 import router from "@/router/index"
11 -import {addrouters} from "@/router/index" 10 +import { addrouters } from "@/router/index"
12 Vue.use(Vuex) 11 Vue.use(Vuex)
13 12
14 const store = new Vuex.Store({ 13 const store = new Vuex.Store({
15 state: { 14 state: {
16 - token: Cookies.get("token"),  
17 - info: "", // 每次刷新都要通过token请求个人信息来筛选动态路由  
18 - routers: [],  
19 - addRouters: [],  
20 - tokenSources:new Map(), 15 + token: "",
  16 + csCode: localStorage.getItem("csCode") || "",
  17 + info: sessionStorage.getItem("info") ? JSON.parse(sessionStorage.getItem("info")) : "", // 每次刷新都要通过token请求个人信息来筛选动态路由
  18 + routers: [],//左侧菜单
  19 + addRouters: sessionStorage.getItem("addRouters") ? JSON.parse(sessionStorage.getItem("addRouters")) : [],//动态路由
  20 + tokenSources: new Map(),//正在请求接口(切换取消请求)
21 }, 21 },
22 mutations: { 22 mutations: {
23 setToken(state, token) { 23 setToken(state, token) {
24 state.token = token 24 state.token = token
25 - Cookies.set("token", token, { expires: 1 / 24 }) 25 + },
  26 + setCode(state, code) {
  27 + state.csCode = code;
  28 + localStorage.setItem("csCode", code)
26 }, 29 },
27 setInfo(state, data) { 30 setInfo(state, data) {
28 state.info = { 31 state.info = {
@@ -33,58 +36,62 @@ const store = new Vuex.Store({ @@ -33,58 +36,62 @@ const store = new Vuex.Store({
33 avatar: data.avatar ? data.avatar : "", 36 avatar: data.avatar ? data.avatar : "",
34 uid: data.uid 37 uid: data.uid
35 } 38 }
36 - localStorage.setItem("info", JSON.stringify(store.getters.info)) 39 + sessionStorage.setItem("info", JSON.stringify(state.info))
37 }, 40 },
38 setRouters: (state, routers) => { 41 setRouters: (state, routers) => {
39 - state.addRouters = routers // 保存动态路由用来addRouter  
40 - state.routers = defaultRouter.concat(routers) // 所有有权限的路由表,用来生成菜单列表 42 + let aRouters = addrouters.filter(item => {
  43 + let path = item.children[0]?.path.replace("/", "")
  44 + return routers?.includes(path)
  45 + })
  46 +
  47 + state.addRouters = aRouters // 保存动态路由用来addRouter
  48 + state.routers = defaultRouter.concat(aRouters) // 所有有权限的路由表,用来生成菜单列表
  49 + sessionStorage.setItem("addRouters", JSON.stringify(routers))
41 }, 50 },
42 - setTokenSources(state,data){  
43 - if(data instanceof Array){ 51 + setTokenSources(state, data) {
  52 + if (data instanceof Array) {
44 state.tokenSources.set(data[0], data[1]) 53 state.tokenSources.set(data[0], data[1])
45 - }else{ 54 + } else {
46 state.tokenSources = new Map() 55 state.tokenSources = new Map()
47 } 56 }
48 }, 57 },
49 - delTokenSources(state,data){ 58 + delTokenSources(state, data) {
50 state.tokenSources.delete(data) 59 state.tokenSources.delete(data)
51 }, 60 },
52 }, 61 },
53 actions: { 62 actions: {
54 - Login({ state,commit }, params) {  
55 - let loginForm={} 63 + Login({ state, commit }, params) {
  64 + let loginForm = {}
56 loginForm.username = params.username; 65 loginForm.username = params.username;
57 loginForm.password = encryptLoginPassword(params.password); 66 loginForm.password = encryptLoginPassword(params.password);
58 - // request.fetchLogin(loginForm).then(res => {  
59 - // if (res.status == 200) {  
60 - // const dataJSON = JSON.parse(b64DecodeUnicode(res.data));  
61 - commit("setToken", "xxxx")  
62 - commit("setInfo", {  
63 - permissions: [  
64 - {  
65 - role: "superAdmin",  
66 - roleName: "超级管理员",  
67 - },  
68 - ],  
69 - name: "张老师",  
70 - // avatar: data.avatar ? data.avatar : "",  
71 - // uid: data.id,  
72 - // authorityRouter:[],  
73 - });  
74 - commit("setRouters", addrouters)  
75 - state.addRouters.forEach((res) => {  
76 - router.addRoute(res);  
77 - });  
78 - console.log()  
79 - if (params.url) {  
80 - window.location.href = params.url;  
81 - } else {  
82 - router.push({ path: "/" })  
83 - }  
84 - // }  
85 - // }) 67 + request.fetchLogin({ ...loginForm }).then(res => {
  68 + let response = res.data
  69 + if (response.status == 0) {
  70 + const userInfo = { ...response.data }
  71 + commit("setToken", "isLogin");
  72 + commit("setInfo", { ...userInfo });
  73 + commit("setRouters", [...userInfo.authorityRouter])
  74 + state.addRouters.forEach((res) => {
  75 + router.addRoute(res);
  76 + });
  77 + router.addRoute({
  78 + path: "*",
  79 + redirect: "/404",
  80 + hidden: true,
  81 + children: []
  82 + })
  83 + console.log()
  84 + if (params.url) {
  85 + window.location.href = params.url;
  86 + } else {
  87 + router.push({ path: "/" })
  88 + }
  89 + }
  90 + }).catch(() => {
  91 + // commit("setToken", Cookies.get("JSESSIONID"));
  92 + })
86 }, 93 },
87 - permissions({ state,commit }, that) { 94 + permissions({ state, commit }, that) {
88 // request.fetchLogin(that.loginForm).then(res => { 95 // request.fetchLogin(that.loginForm).then(res => {
89 // if (res.status == 200) { 96 // if (res.status == 200) {
90 commit("setToken", "xxxx") 97 commit("setToken", "xxxx")
@@ -98,13 +105,39 @@ const store = new Vuex.Store({ @@ -98,13 +105,39 @@ const store = new Vuex.Store({
98 name: "李老师", 105 name: "李老师",
99 // avatar: data.avatar ? data.avatar : "", 106 // avatar: data.avatar ? data.avatar : "",
100 // uid: data.id, 107 // uid: data.id,
101 - // authorityRouter:[], 108 + authorityRouter:[
  109 + "examinationPaper",
  110 + "examinationPaperAdd",
  111 + "examinationPaperEdit",
  112 + "examinationPaperRecycle",
  113 + "ask",
  114 + "askAnalysis",
  115 + "test",
  116 + "testAnalysis",
  117 + "portrait",
  118 + "setUpConglomerate",
  119 + "setUpAccount",
  120 + "setUpSchool",
  121 + "setUpTeacher",
  122 + "setUpStudent",
  123 + "card",
  124 + "device",
  125 + "analysis",
  126 + "down",
  127 + "downClient",
  128 + "dataSync"
  129 + ],
102 }); 130 });
103 - commit("setRouters", addrouters) 131 + commit("setRouters", authorityRouter)
104 state.addRouters.forEach((res) => { 132 state.addRouters.forEach((res) => {
105 - that.$router.addRoute(res); 133 + router.addRoute(res);
106 }); 134 });
107 - that.$router.push({ path: "/" }) 135 + router.addRoute({
  136 + path: "*",
  137 + redirect: "/404",
  138 + hidden: true,
  139 + children: []
  140 + })
108 // } 141 // }
109 // }) 142 // })
110 } 143 }
@@ -112,6 +145,7 @@ const store = new Vuex.Store({ @@ -112,6 +145,7 @@ const store = new Vuex.Store({
112 getters: { 145 getters: {
113 addRouters: state => state.addRouters, 146 addRouters: state => state.addRouters,
114 token: state => state.token, 147 token: state => state.token,
  148 + code: state => state.csCode,
115 info: state => state.info, 149 info: state => state.info,
116 routers: state => state.routers, 150 routers: state => state.routers,
117 logoShow: state => state.layoutStore.logoShow, 151 logoShow: state => state.layoutStore.logoShow,
src/utils/index.js
@@ -9,7 +9,7 @@ const encryptIV = "D076D35C" @@ -9,7 +9,7 @@ const encryptIV = "D076D35C"
9 * @param data: 待加密数据 9 * @param data: 待加密数据
10 * @returns 加密结果 10 * @returns 加密结果
11 */ 11 */
12 -export function encryptLoginPassword(data){ 12 +export function encryptLoginPassword(data) {
13 const secret = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjh2ei17z5k2r4VzbqoSCE6RmYzWySJTgVQYulgfVM+vqcDoUE4cFB4XCFA2lHWjjpsuJP1EtwKlvUgxo5okr3x/a88o8eERxBynnVQZbEYpKteW5aqSEb/g1yPLWnKV88b/ED445ITYbZZuInRo5lkCvd6QEjL6d2Fch6mEo5awYXC4/S4BJf9YlYRhGzR7wpiXCLvyBHQ4iSIIDNpmrPBPQzGP0rx09aDu54kz/42CR6SX2OqXSi4ZoieqkPFl/iuX4RoD/NKKR+haDn1UzoD3k1WzHSTBFFs27rxRpxfBUZzfXQeskgKyw/Slcl3jUFizczsY4CLgTRrfey48Q6QIDAQAB'; 13 const secret = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjh2ei17z5k2r4VzbqoSCE6RmYzWySJTgVQYulgfVM+vqcDoUE4cFB4XCFA2lHWjjpsuJP1EtwKlvUgxo5okr3x/a88o8eERxBynnVQZbEYpKteW5aqSEb/g1yPLWnKV88b/ED445ITYbZZuInRo5lkCvd6QEjL6d2Fch6mEo5awYXC4/S4BJf9YlYRhGzR7wpiXCLvyBHQ4iSIIDNpmrPBPQzGP0rx09aDu54kz/42CR6SX2OqXSi4ZoieqkPFl/iuX4RoD/NKKR+haDn1UzoD3k1WzHSTBFFs27rxRpxfBUZzfXQeskgKyw/Slcl3jUFizczsY4CLgTRrfey48Q6QIDAQAB';
14 // 新建JSEncrypt对象 14 // 新建JSEncrypt对象
15 let encryptor = new JSEncrypt(); 15 let encryptor = new JSEncrypt();
@@ -25,7 +25,7 @@ export function encryptLoginPassword(data){ @@ -25,7 +25,7 @@ export function encryptLoginPassword(data){
25 * @param data: 待加密数据 25 * @param data: 待加密数据
26 * @returns 加密结果 26 * @returns 加密结果
27 */ 27 */
28 -export function encryptData(secret, data){ 28 +export function encryptData(secret, data) {
29 // 新建JSEncrypt对象 29 // 新建JSEncrypt对象
30 let encryptor = new JSEncrypt(); 30 let encryptor = new JSEncrypt();
31 // 设置公钥 31 // 设置公钥
@@ -35,7 +35,7 @@ export function encryptData(secret, data){ @@ -35,7 +35,7 @@ export function encryptData(secret, data){
35 } 35 }
36 36
37 // 深度复制 37 // 深度复制
38 -export function deepClone (obj) { 38 +export function deepClone(obj) {
39 let result = Array.isArray(obj) ? [] : {} 39 let result = Array.isArray(obj) ? [] : {}
40 for (let key in obj) { 40 for (let key in obj) {
41 if (obj.hasOwnProperty(key)) { 41 if (obj.hasOwnProperty(key)) {
@@ -74,7 +74,7 @@ export function deepClone (obj) { @@ -74,7 +74,7 @@ export function deepClone (obj) {
74 // } 74 // }
75 75
76 // 随机生成由字母+数字的字符串 76 // 随机生成由字母+数字的字符串
77 -export function randomWord (randomFlag, min, max) { 77 +export function randomWord(randomFlag, min, max) {
78 // randomFlag: Boolean 是否随机个数 78 // randomFlag: Boolean 是否随机个数
79 // min 最少个数 79 // min 最少个数
80 // max 最大个数 80 // max 最大个数
@@ -94,7 +94,7 @@ export function randomWord (randomFlag, min, max) { @@ -94,7 +94,7 @@ export function randomWord (randomFlag, min, max) {
94 } 94 }
95 95
96 // 判断数组中是否存在相同值 96 // 判断数组中是否存在相同值
97 -export function hasRepeatValue (arr, key = null) { 97 +export function hasRepeatValue(arr, key = null) {
98 if (key) arr = arr.map(d => d[key]) 98 if (key) arr = arr.map(d => d[key])
99 if (arr.length) { 99 if (arr.length) {
100 let nameNum = arr.reduce((pre, cur) => { 100 let nameNum = arr.reduce((pre, cur) => {
@@ -111,7 +111,7 @@ export function hasRepeatValue (arr, key = null) { @@ -111,7 +111,7 @@ export function hasRepeatValue (arr, key = null) {
111 } 111 }
112 112
113 // 获取cookie值 113 // 获取cookie值
114 -export function getCookie (name, defaultValue) { 114 +export function getCookie(name, defaultValue) {
115 const result = new RegExp("(^| )" + name + "=([^;]*)(;|$)") 115 const result = new RegExp("(^| )" + name + "=([^;]*)(;|$)")
116 return result[0] === document.cookie.match(result[1]) ? unescape(result[0][2]) : defaultValue 116 return result[0] === document.cookie.match(result[1]) ? unescape(result[0][2]) : defaultValue
117 } 117 }
@@ -120,19 +120,19 @@ export function getCookie (name, defaultValue) { @@ -120,19 +120,19 @@ export function getCookie (name, defaultValue) {
120 /** 120 /**
121 * base64转化unicode 121 * base64转化unicode
122 */ 122 */
123 - export function b64DecodeUnicode(str) { 123 +export function b64DecodeUnicode(str) {
124 let uni; 124 let uni;
125 try { 125 try {
126 // atob 经过 base-64 编码的字符串进行解码 126 // atob 经过 base-64 编码的字符串进行解码
127 uni = decodeURIComponent(atob(str).split('').map(function (c) { 127 uni = decodeURIComponent(atob(str).split('').map(function (c) {
128 return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); 128 return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
129 }).join('')); 129 }).join(''));
130 - } catch (e) {} 130 + } catch (e) { }
131 return uni; 131 return uni;
132 } 132 }
133 133
134 // base64ToFile 134 // base64ToFile
135 -export function base64ToFile (base64Data, tempfilename, contentType) { 135 +export function base64ToFile(base64Data, tempfilename, contentType) {
136 contentType = contentType || "" 136 contentType = contentType || ""
137 var sliceSize = 1024 137 var sliceSize = 1024
138 var byteCharacters = atob(base64Data) 138 var byteCharacters = atob(base64Data)
@@ -155,7 +155,7 @@ export function base64ToFile (base64Data, tempfilename, contentType) { @@ -155,7 +155,7 @@ export function base64ToFile (base64Data, tempfilename, contentType) {
155 } 155 }
156 156
157 // 将base64转换为文件 157 // 将base64转换为文件
158 -export function dataURLtoFile (dataurl, filename) { 158 +export function dataURLtoFile(dataurl, filename) {
159 var arr = dataurl.split(",") 159 var arr = dataurl.split(",")
160 var mime = arr[0].match(/:(.*?);/)[1] 160 var mime = arr[0].match(/:(.*?);/)[1]
161 var bstr = atob(arr[1]) 161 var bstr = atob(arr[1])
@@ -168,7 +168,7 @@ export function dataURLtoFile (dataurl, filename) { @@ -168,7 +168,7 @@ export function dataURLtoFile (dataurl, filename) {
168 } 168 }
169 169
170 // 将图片转换为Base64 170 // 将图片转换为Base64
171 -export function getImgToBase64 (url, callback, outputFormat) { 171 +export function getImgToBase64(url, callback, outputFormat) {
172 var canvas = document.createElement("canvas") 172 var canvas = document.createElement("canvas")
173 var ctx = canvas.getContext("2d") 173 var ctx = canvas.getContext("2d")
174 var img = new Image() 174 var img = new Image()
@@ -185,7 +185,7 @@ export function getImgToBase64 (url, callback, outputFormat) { @@ -185,7 +185,7 @@ export function getImgToBase64 (url, callback, outputFormat) {
185 } 185 }
186 186
187 // 转换级联下拉数据 187 // 转换级联下拉数据
188 -export function loopOptions (list, option = {}) { 188 +export function loopOptions(list, option = {}) {
189 option = { 189 option = {
190 value: "id", 190 value: "id",
191 label: "name", 191 label: "name",
@@ -206,7 +206,7 @@ export function loopOptions (list, option = {}) { @@ -206,7 +206,7 @@ export function loopOptions (list, option = {}) {
206 } 206 }
207 207
208 // 通过Id获取级联数据id数组 208 // 通过Id获取级联数据id数组
209 -export function getTreeIds (tree, currentId, key = "id") { 209 +export function getTreeIds(tree, currentId, key = "id") {
210 let parent = {} 210 let parent = {}
211 let pid = {} 211 let pid = {}
212 const loop = (list, level) => { 212 const loop = (list, level) => {
@@ -233,16 +233,40 @@ export function getTreeIds (tree, currentId, key = "id") { @@ -233,16 +233,40 @@ export function getTreeIds (tree, currentId, key = "id") {
233 return result 233 return result
234 } 234 }
235 235
236 -// 秒转换时分秒  
237 -export function transverterMss (result) {  
238 - var h = Math.floor(result / 3600) < 10 ? "0" + Math.floor(result / 3600) : Math.floor(result / 3600)  
239 - var m = Math.floor((result / 60 % 60)) < 10 ? "0" + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60))  
240 - var s = Math.floor((result % 60)) < 10 ? "0" + Math.floor((result % 60)) : Math.floor((result % 60))  
241 - return h + ":" + m + ":" + s 236 +/*
  237 + * 格式化时间
  238 + * yyyy-MM-dd hh:mm:ss
  239 + * */
  240 +export function formatDate(date, fmt) {
  241 + if (!date || date == null) return null;
  242 + if (isNaN(date)) {
  243 + return date;
  244 + }
  245 + let format = fmt || "yyyy-MM-dd hh:mm:ss";
  246 +
  247 + let dates = new Date(Number(date));
  248 +
  249 + let formatObj = {
  250 + y: dates.getFullYear(),
  251 + M: dates.getMonth() + 1,
  252 + d: dates.getDate(),
  253 + h: dates.getHours(),
  254 + m: dates.getMinutes(),
  255 + s: dates.getSeconds(),
  256 + };
  257 + let time_str = format.replace(/(y|M|d|h|m|s)+/g, (result, key) => {
  258 + let value = formatObj[key];
  259 + if (result.length > 0 && value < 10) {
  260 + value = "0" + value;
  261 + }
  262 + return value || 0;
  263 + });
  264 + return time_str;
242 } 265 }
243 266
  267 +
244 // 获取日期时间戳 268 // 获取日期时间戳
245 -export function getTime (dayNum) { 269 +export function getTime(dayNum) {
246 var myDate = new Date() 270 var myDate = new Date()
247 var lw = new Date(myDate - 1000 * 60 * 60 * 24 * dayNum)// 最后一个数字多少天前的意思 271 var lw = new Date(myDate - 1000 * 60 * 60 * 24 * dayNum)// 最后一个数字多少天前的意思
248 var lastY = lw.getFullYear() 272 var lastY = lw.getFullYear()
@@ -256,7 +280,7 @@ export function getTime (dayNum) { @@ -256,7 +280,7 @@ export function getTime (dayNum) {
256 } 280 }
257 281
258 // 获取几天之前日期 282 // 获取几天之前日期
259 -export function getData (dayNum) { 283 +export function getData(dayNum) {
260 var myDate = new Date() 284 var myDate = new Date()
261 var lw = new Date(myDate - 1000 * 60 * 60 * 24 * dayNum)// 最后一个数字多少天前的意思 285 var lw = new Date(myDate - 1000 * 60 * 60 * 24 * dayNum)// 最后一个数字多少天前的意思
262 var lastY = lw.getFullYear() 286 var lastY = lw.getFullYear()
@@ -267,7 +291,7 @@ export function getData (dayNum) { @@ -267,7 +291,7 @@ export function getData (dayNum) {
267 } 291 }
268 292
269 // 日期转换时间戳 293 // 日期转换时间戳
270 -export function getNewTime (dayNum) { 294 +export function getNewTime(dayNum) {
271 var b = dayNum.split(/\D/) 295 var b = dayNum.split(/\D/)
272 var date = new Date(b[0], b[1] - 1, b[2]) 296 var date = new Date(b[0], b[1] - 1, b[2])
273 var time = date.getTime() 297 var time = date.getTime()
@@ -297,4 +321,75 @@ export function getURLParams(variable) { @@ -297,4 +321,75 @@ export function getURLParams(variable) {
297 } 321 }
298 } 322 }
299 return variable ? data : obj 323 return variable ? data : obj
300 -}  
301 \ No newline at end of file 324 \ No newline at end of file
  325 +}
  326 +
  327 +/**
  328 + * 校验答案
  329 + * @param {*} s 源字符串
  330 + * @param {*} questionType 题型,2单选 3多选
  331 + * @param {*} optionCount 选项数目
  332 + * @param {*} questionCount 题目数目
  333 + */
  334 +function filtterChar(s, b, optionCount) {
  335 + const ms = "ABCDEFG";
  336 + let rs = "";
  337 + for (let i = 0; i < s.length; i++) {
  338 + let c = s[i];
  339 + if (c == ',' || c == ' ' || c == ',') {
  340 + if (!b) {
  341 + continue;
  342 + }
  343 + c = ',';
  344 + }
  345 + else if (c < 'A' || c >= ms[optionCount]) {
  346 + continue;
  347 + }
  348 + rs += c;
  349 + }
  350 + return rs;
  351 +}
  352 +
  353 +function removeDup(s) {
  354 + const ms = "ABCDEFG";
  355 + let rs = "";
  356 + for (let i = 0; i < ms.length; i++) {
  357 + if (s.indexOf(ms[i]) >= 0) {
  358 + rs += ms[i];
  359 + }
  360 + }
  361 + return rs;
  362 +}
  363 +export function checkAnswer(s, questionType, optionCount = 4, questionCount = 1) {
  364 + if (optionCount > 10 || questionCount < 1) {
  365 + return null;
  366 + }
  367 + let pre = s;
  368 + s = s.toUpperCase();
  369 + s = filtterChar(s, questionType == 3 && questionCount > 1, optionCount);
  370 + if (questionType == 2) {//单选
  371 + console.log(s.length + " " + questionCount);
  372 + if (s.length > questionCount) {
  373 + s = s.substring(s.length - questionCount, s.length);
  374 + }
  375 + }
  376 + else if (questionType == 3) {//多选
  377 + //允许逗号
  378 + let ss = s.split(",");
  379 + let len = questionCount;
  380 + if (len > ss.length) {
  381 + len = ss.length;
  382 + }
  383 + let rs = "";
  384 + for (let i = 0; i < len; i++) {
  385 + rs += removeDup(ss[i]);
  386 + if (i < len - 1) {
  387 + rs += ',';
  388 + }
  389 + }
  390 + s = rs;
  391 + }
  392 + else {
  393 + return null;
  394 + }
  395 + return s;
  396 +}
src/views/ask/analysis.vue
1 <template> 1 <template>
2 - <div>报表分析</div> 2 + <div>
  3 + <back-box>
  4 + <template slot="title">
  5 + <span>单课分析</span>
  6 + </template>
  7 + </back-box>
  8 + <div class="tab-box">
  9 + <span class="tab-item active">答题表现</span>
  10 + <span class="tab-item">学生问答表现</span>
  11 + <span class="tab-item">学生互动表现</span>
  12 + <span class="tab-item">签到明细</span>
  13 + </div>
  14 + </div>
3 </template> 15 </template>
4 16
5 <script> 17 <script>
6 -export default {  
7 -  
8 -} 18 +export default {};
9 </script> 19 </script>
10 20
11 -<style>  
12 - 21 +<style lang="scss" scoped>
  22 +.tab-box {
  23 + width: 800px;
  24 + margin: 20px auto;
  25 + background: #f8f8f8;
  26 + border-radius: 20px;
  27 + display: flex;
  28 + .tab-item {
  29 + flex: 1;
  30 + height: 40px;
  31 + line-height: 40px;
  32 + text-align: center;
  33 + font-size: 16px;
  34 + color: #666;
  35 + font-weight: 500;
  36 + background: transparent;
  37 + border-radius: 20px;
  38 + &.active {
  39 + background: #667ffd;
  40 + color: #fff;
  41 + }
  42 + }
  43 +}
13 </style> 44 </style>
14 \ No newline at end of file 45 \ No newline at end of file
src/views/ask/index.vue
1 <template> 1 <template>
2 - <div>随堂问报表  
3 - <router-link to="/askAnalysis">报表分析</router-link>  
4 - 2 + <div>
  3 + <back-box>
  4 + <template slot="title">
  5 + <span>问答-数据报表</span>
  6 + </template>
  7 + </back-box>
  8 + <div class="answer-header">
  9 + <div class="sel-box">
  10 + <el-select
  11 + class="sel"
  12 + v-model="query.clazzId"
  13 + placeholder=""
  14 + @change="changClazz"
  15 + >
  16 + <el-option
  17 + v-for="item in classList"
  18 + :key="item.value"
  19 + :label="item.label"
  20 + :value="item.value"
  21 + >{{ item.label }}
  22 + </el-option>
  23 + </el-select>
  24 + <el-select
  25 + v-if="role == '班主任'"
  26 + class="sel"
  27 + multiple
  28 + collapse-tags
  29 + v-model="query.subjectId"
  30 + placeholder=""
  31 + @change="_QueryData"
  32 + >
  33 + <el-option
  34 + v-for="item in subjectList"
  35 + :key="item.value"
  36 + :label="item.label"
  37 + :value="item.value"
  38 + >
  39 + </el-option>
  40 + </el-select>
  41 + <el-select
  42 + v-else
  43 + class="sel"
  44 + v-model="query.subjectId"
  45 + placeholder=""
  46 + @change="_QueryData"
  47 + >
  48 + <el-option
  49 + v-for="item in subjectList"
  50 + :key="item.value"
  51 + :label="item.label"
  52 + :value="item.value"
  53 + >
  54 + </el-option>
  55 + </el-select>
  56 + <div class="d1">
  57 + <el-date-picker
  58 + v-model="query.startDay"
  59 + type="date"
  60 + @change="handleChangeTimeStart"
  61 + placeholder="选择日期时间"
  62 + value-format="yyyy-MM-dd"
  63 + >
  64 + </el-date-picker>
  65 + ~
  66 + <el-date-picker
  67 + v-model="query.endDay"
  68 + type="date"
  69 + placeholder="选择日期时间"
  70 + @change="handleChangeTimeEnd"
  71 + value-format="yyyy-MM-dd"
  72 + >
  73 + </el-date-picker>
  74 + </div>
  75 + <p class="p1">
  76 + <span @click="setDate(1)" :class="[date == 1 ? 'active' : '', 's1']"
  77 + >今天</span
  78 + >
  79 + <span @click="setDate(2)" :class="[date == 2 ? 'active' : '', 's1']"
  80 + >昨天</span
  81 + >
  82 + <span @click="setDate(3)" :class="[date == 3 ? 'active' : '', 's1']"
  83 + >本周</span
  84 + >
  85 + </p>
  86 + <el-button type="primary" round @click="_QueryData()">筛选</el-button>
  87 + </div>
  88 + </div>
  89 + <div class="table-box">
  90 + <el-radio-group v-model="tabIndex" style="margin-bottom: 20px">
  91 + <el-radio-button :label="1">单课时报表</el-radio-button>
  92 + <el-radio-button :label="2" v-if="this.role != '班主任'"
  93 + >阶段问答报表</el-radio-button
  94 + >
  95 + <el-radio-button :label="3">阶段互动报表</el-radio-button>
  96 + </el-radio-group>
  97 + <p class="table-tit" v-if="tabIndex != 1">
  98 + <span>总课时数:10</span>
  99 + <span>互动总数:22</span>
  100 + </p>
  101 + <div v-if="tabIndex == 1">
  102 + <el-table
  103 + :data="tableData"
  104 + border
  105 + style="width: 100%"
  106 + :default-sort="{ prop: 'canyudu', order: 'descending' }"
  107 + >
  108 + <el-table-column
  109 + prop="keshi"
  110 + label="课时"
  111 + align="center"
  112 + ></el-table-column>
  113 + <el-table-column
  114 + prop="zongshu"
  115 + label="题目总数"
  116 + align="center"
  117 + width="100"
  118 + ></el-table-column>
  119 + <el-table-column
  120 + prop="shijian"
  121 + label="上课时间"
  122 + align="center"
  123 + ></el-table-column>
  124 + <el-table-column
  125 + prop="canyudu"
  126 + label="参与度"
  127 + sortable
  128 + align="center"
  129 + > <template slot-scope="scoped">{{scoped.row.canyudu}}%</template></el-table-column>
  130 + <el-table-column
  131 + prop="zhengque"
  132 + label="已答总正确率"
  133 + sortable
  134 + align="center"
  135 + >
  136 + <template slot-scope="scoped">{{scoped.row.zhengque}}%</template>
  137 + </el-table-column>
  138 + <el-table-column
  139 + prop="allzheng"
  140 + label="班级总正确率"
  141 + sortable
  142 + align="center"
  143 + ><template slot-scope="scoped">{{scoped.row.allzheng}}%</template></el-table-column>
  144 + <el-table-column label="操作" align="center">
  145 + <template slot-scope="scoped">
  146 + <el-tooltip effect="dark" content="详情" placement="left">
  147 + <el-button
  148 + type="primary"
  149 + circle
  150 + size="mini"
  151 + icon="fa fa-arrow-right"
  152 + @click="linkTo(scoped.row)"
  153 + ></el-button>
  154 + </el-tooltip>
  155 + <el-tooltip effect="dark" content="修改答案" placement="right">
  156 + <el-button
  157 + type="primary"
  158 + circle
  159 + size="mini"
  160 + icon="fa fa-file-text"
  161 + @click="edit(scoped.row)"
  162 + ></el-button>
  163 + </el-tooltip>
  164 + </template>
  165 + </el-table-column>
  166 + </el-table>
  167 + </div>
  168 + <div v-if="tabIndex == 2">
  169 + <el-table
  170 + :data="tableAsk"
  171 + border
  172 + style="width: 100%"
  173 + :default-sort="{ prop: 'cishu', order: 'descending' }"
  174 + >
  175 + <el-table-column
  176 + prop="xuehao"
  177 + label="学号"
  178 + align="center"
  179 + ></el-table-column>
  180 + <el-table-column
  181 + prop="xingming"
  182 + label="姓名"
  183 + align="center"
  184 + width="100"
  185 + ></el-table-column>
  186 + <el-table-column
  187 + prop="cishu"
  188 + label="累计答题次数"
  189 + sortable
  190 + align="center"
  191 + ></el-table-column>
  192 + <el-table-column
  193 + prop="dadui"
  194 + label="累计答对次数"
  195 + sortable
  196 + align="center"
  197 + ></el-table-column>
  198 + <el-table-column
  199 + prop="canyudu"
  200 + label="总参与度"
  201 + sortable
  202 + align="center"
  203 + > <template slot-scope="scoped">{{scoped.row.canyudu}}%</template></el-table-column>
  204 + <el-table-column
  205 + prop="allzheng"
  206 + label="总正确率"
  207 + sortable
  208 + align="center"
  209 + > <template slot-scope="scoped">{{scoped.row.allzheng}}%</template></el-table-column>
  210 + <el-table-column
  211 + prop="yidazheng"
  212 + label="已答总正确率"
  213 + sortable
  214 + align="center"
  215 + >
  216 + <template slot-scope="scoped">{{scoped.row.yidazheng}}%</template>
  217 + </el-table-column>
  218 + <el-table-column
  219 + prop="zongpaiming"
  220 + label="总正确率班排名"
  221 + sortable
  222 + align="center"
  223 + ></el-table-column>
  224 + </el-table>
  225 + </div>
  226 + <div v-if="tabIndex == 3">
  227 + <el-table
  228 + :data="tableAsk"
  229 + border
  230 + style="width: 100%"
  231 + :default-sort="{ prop: 'cishu', order: 'descending' }"
  232 + >
  233 + <el-table-column
  234 + prop="xuehao"
  235 + label="学号"
  236 + align="center"
  237 + ></el-table-column>
  238 + <el-table-column
  239 + prop="xingming"
  240 + label="姓名"
  241 + align="center"
  242 + width="100"
  243 + ></el-table-column>
  244 + <el-table-column
  245 + prop="cishu"
  246 + label="抢答成功次数"
  247 + sortable
  248 + align="center"
  249 + ></el-table-column>
  250 + <el-table-column
  251 + prop="dadui"
  252 + label="答对次数"
  253 + sortable
  254 + align="center"
  255 + ></el-table-column>
  256 + <el-table-column
  257 + prop="chouda"
  258 + label="抽答次数"
  259 + sortable
  260 + align="center"
  261 + ></el-table-column>
  262 + <el-table-column
  263 + prop="choudadui"
  264 + label="抽答答对次数"
  265 + sortable
  266 + align="center"
  267 + ></el-table-column>
  268 + <el-table-column
  269 + prop="canyu"
  270 + label="参与得分"
  271 + sortable
  272 + align="center"
  273 + ></el-table-column>
  274 + <el-table-column
  275 + prop="duicuo"
  276 + label="对错得分"
  277 + sortable
  278 + align="center"
  279 + ></el-table-column>
  280 + </el-table>
  281 + </div>
  282 + <p class="down" v-if="tabIndex == 3||tabIndex == 2">
  283 + <el-button type="info" plain round icon="fa fa-cloud-download">导出报表</el-button>
  284 + </p>
  285 + </div>
  286 + <el-dialog :visible.sync="dialogVisible" width="400" center>
  287 + <div slot="title">
  288 + <p>
  289 + <!-- 设置答案 <i class="fa fa-exchange" @click="editType = !editType"></i> -->
  290 + 设置答案
  291 + </p>
  292 + </div>
  293 + <div v-show="editType">
  294 + <div v-for="(item, index) in form.questionList" :key="index">
  295 + <template v-for="(subQuestions, indexs) in item.subQuestions">
  296 + <div
  297 + class="sub-questions"
  298 + :key="indexs"
  299 + v-if="subQuestions.correctAnswer"
  300 + >
  301 + <div class="qs-num">题{{ subQuestions.questionIndex }}</div>
  302 + <div class="qs-options qs-options2">
  303 + <p v-if="subQuestions.questionType == 4" class="answer-box">
  304 + <span
  305 + class="answer-s"
  306 + :class="subQuestions.correctAnswer == 1 ? 'active' : ''"
  307 + @click="subQuestions.correctAnswer = 1"
  308 + >✓</span
  309 + >
  310 + <span
  311 + class="answer-s"
  312 + :class="subQuestions.correctAnswer == 2 ? 'active' : ''"
  313 + @click="subQuestions.correctAnswer = 2"
  314 + >✗</span
  315 + >
  316 + </p>
  317 + <p v-if="subQuestions.questionType == 3" class="answer-box">
  318 + <span
  319 + class="answer-s"
  320 + v-for="option in subQuestions.answerOptions"
  321 + :class="
  322 + subQuestions.correctAnswer.includes(option)
  323 + ? 'active'
  324 + : ''
  325 + "
  326 + :key="option"
  327 + @click="changAnswer(subQuestions, option)"
  328 + >{{ option }}</span
  329 + >
  330 + </p>
  331 + <p v-if="subQuestions.questionType == 2" class="answer-box">
  332 + <span
  333 + class="answer-s"
  334 + v-for="option in subQuestions.answerOptions"
  335 + :class="
  336 + subQuestions.correctAnswer == option ? 'active' : ''
  337 + "
  338 + :key="option"
  339 + @click="subQuestions.correctAnswer = option"
  340 + >{{ option }}</span
  341 + >
  342 + </p>
  343 + </div>
  344 + </div>
  345 + </template>
  346 + </div>
  347 + </div>
  348 + <!-- <div v-show="!editType">
  349 + <p class="dia-tips">
  350 + 请点击选项按钮设置答案,多选题题目之间用“,”隔开,若添加5道题:“AC,AD,BD,AC,CD”
  351 + </p>
  352 + <div class="dia-question-box">
  353 + <div v-for="(item, index) in form2.questionList" :key="index">
  354 + <template v-for="(items, indexs) in item.subQuestions">
  355 + <div class="set-questions" :key="indexs">
  356 + <div class="qs-num">
  357 + <p>{{ items.name }}</p>
  358 + <p>共{{ items.list.length }}题</p>
  359 + </div>
  360 + <div class="qs-options">
  361 + <p class="ipt">
  362 + <el-input
  363 + v-model="items.answerList"
  364 + @keydown.native="keydownAnswer($event)"
  365 + ></el-input>
  366 + </p>
  367 + <p class="answer-box">
  368 + <template v-if="items.list[0].questionType == 4">
  369 + <span
  370 + class="answer-s active"
  371 + @click="
  372 + items.answerList.length < items.list.length
  373 + ? (items.answerList += '✓')
  374 + : ''
  375 + "
  376 + >✓</span
  377 + >
  378 + <span
  379 + class="answer-s active"
  380 + @click="
  381 + items.answerList.length < items.list.length
  382 + ? (items.answerList += '✗')
  383 + : ''
  384 + "
  385 + >✗</span
  386 + >
  387 + </template>
  388 + <template v-if="items.list[0].questionType == 3">
  389 + <span
  390 + class="answer-s active"
  391 + v-for="option in items.list[0].answerOptions"
  392 + :key="option"
  393 + @click="setAnswer(items,option)"
  394 + >{{ option }}</span
  395 + >
  396 + <span
  397 + class="answer-s active"
  398 + @click="
  399 + items.answerList.split(',').length < items.list.length
  400 + ? (items.answerList += ',')
  401 + : ''
  402 + "
  403 + >,</span
  404 + >
  405 + </template>
  406 + <template
  407 + v-if="items.list[0].questionType == 2"
  408 + class="answer-box"
  409 + >
  410 + <span
  411 + class="answer-s active"
  412 + v-for="option in items.list[0].answerOptions"
  413 + :key="option"
  414 + @click="
  415 + items.answerList.length < items.list.length
  416 + ? (items.answerList += option)
  417 + : ''
  418 + "
  419 + >{{ option }}</span
  420 + >
  421 + </template>
  422 + <span
  423 + class="answer-s delButton"
  424 + @click="items.answerList = items.answerList.slice(0, -1)"
  425 + >x</span
  426 + >
  427 + <span
  428 + class="answer-s ac"
  429 + @click="items.answerList = ''"
  430 + >AC</span
  431 + >
  432 + </p>
  433 + </div>
  434 + </div>
  435 + </template>
  436 + </div>
  437 + </div>
  438 + </div> -->
  439 + <div slot="footer">
  440 + <el-button class="dia-btn" type="primary" @click="saveAnswer"
  441 + >确 定</el-button
  442 + >
  443 + <el-button class="dia-btn" type="danger" @click="dialogVisible = false"
  444 + >取 消</el-button
  445 + >
  446 + </div>
  447 + </el-dialog>
5 </div> 448 </div>
6 </template> 449 </template>
7 450
8 <script> 451 <script>
  452 +import { formatDate, deepClone,checkAnswer } from "utils";
9 export default { 453 export default {
10 -  
11 -} 454 + data() {
  455 + return {
  456 + role: "",
  457 + loading: false,
  458 + dialogVisible: false, //修改答案
  459 + editType: true, //修改答案模式
  460 + editId: "",
  461 + form: { questionList: [] },
  462 + form2: { questionList: [] },
  463 + date: "", //今天-昨天-本周
  464 + query: {
  465 + //搜索条件
  466 + clazzId: "",
  467 + subjectId: "",
  468 + startDay: "",
  469 + endDay: "",
  470 + day: "",
  471 + },
  472 + classList: [], //班级
  473 + subjectList: [], //科目
  474 + tabIndex: 1, //选项卡
  475 + tableData: [
  476 + //单课时报表
  477 + {
  478 + id: 1,
  479 + keshi: "课时一",
  480 + zongshu: 10,
  481 + shijian: "2022-11-9 21:30至22:30",
  482 + canyudu: 60,
  483 + zhengque: 90,
  484 + allzheng: 80,
  485 + questionList: [
  486 + {
  487 + questionTitle: "f",
  488 + score: 1,
  489 + subQuestions: [
  490 + {
  491 + questionIndex: 1,
  492 + questionType: 2,
  493 + score: 1,
  494 + partScore: 0,
  495 + selectNum: 4,
  496 + answerOptions: ["A", "B", "C", "D"],
  497 + correctAnswer: "B",
  498 + },
  499 + {
  500 + questionIndex: 2,
  501 + questionType: 2,
  502 + score: 1,
  503 + partScore: 0,
  504 + selectNum: 4,
  505 + answerOptions: ["A", "B", "C", "D", "E", "F"],
  506 + correctAnswer: "A",
  507 + },
  508 + {
  509 + questionIndex: 2,
  510 + questionType: 3,
  511 + score: 1,
  512 + partScore: 0,
  513 + selectNum: 4,
  514 + answerOptions: ["A", "B", "C", "D", "E", "F"],
  515 + correctAnswer: "AB",
  516 + },
  517 + {
  518 + questionIndex: 2,
  519 + questionType: 3,
  520 + score: 1,
  521 + partScore: 0,
  522 + selectNum: 4,
  523 + answerOptions: ["A", "B", "C", "D", "E", "F"],
  524 + correctAnswer: "AB",
  525 + },
  526 + {
  527 + questionIndex: 3,
  528 + questionType: 4,
  529 + score: 1,
  530 + partScore: 0,
  531 + selectNum: 0,
  532 + answerOptions: [],
  533 + correctAnswer: "1",
  534 + },
  535 + ],
  536 + },
  537 + ],
  538 + },
  539 + {
  540 + id: 2,
  541 + keshi: "课时二",
  542 + zongshu: 8,
  543 + shijian: "2022-11-10 21:30至22:30",
  544 + canyudu: 70,
  545 + zhengque: 80,
  546 + allzheng: 60,
  547 + questionList: [
  548 + {
  549 + questionTitle: "a",
  550 + score: 1,
  551 + subQuestions: [
  552 + {
  553 + questionIndex: 2,
  554 + questionType: 3,
  555 + score: 1,
  556 + partScore: 0,
  557 + selectNum: 4,
  558 + answerOptions: ["A", "B", "C", "D"],
  559 + correctAnswer: "A,C",
  560 + },
  561 + ],
  562 + },
  563 + ],
  564 + },
  565 + ],
  566 + tableAsk:[
  567 + {
  568 + xuehao: 1,
  569 + xingming: "丁芳菲",
  570 + cishu: 5,
  571 + dadui: 60,
  572 + canyudu: 90,
  573 + allzheng: 80,
  574 + yidazheng:50,
  575 + zongpaiming:5
  576 + },
  577 + {
  578 + xuehao: 1,
  579 + xingming: "丁芳菲2",
  580 + cishu: 3,
  581 + dadui: 20,
  582 + canyudu: 80,
  583 + allzheng: 60,
  584 + yidazheng:65,
  585 + zongpaiming:4
  586 + }
  587 + ],
  588 + tableStage:[
  589 + {
  590 + xuehao: 1,
  591 + xingming: "丁芳菲",
  592 + cishu: 5,
  593 + dadui: 60,
  594 + chouda: 90,
  595 + choudadui: 80,
  596 + canyu:50,
  597 + duicuo:5
  598 + }
  599 + ]
  600 + };
  601 + },
  602 + async created() {
  603 + this.role = this.$store.getters.info.permissions[0]?.roleName;
  604 + if (this.role == "班主任") {
  605 + this.query.subjectId = [];
  606 + }
  607 + // await this._QueryClassList();
  608 + // await this._QuerySubjectList();
  609 + // await this.setDate(1);
  610 + let startDay = this.query?.startDay;
  611 + if (!startDay) {
  612 + this.query.startDay = new Date();
  613 + this.query.endDay = new Date();
  614 + }
  615 + },
  616 + methods: {
  617 + linkTo(obj) {
  618 + //去详情
  619 + this.$router.push({
  620 + path: "/askAnalysis",
  621 + query: {
  622 + id: obj.id,
  623 + },
  624 + });
  625 + },
  626 + setSubPro(type) {
  627 + let tit;
  628 + switch (type) {
  629 + case 2:
  630 + tit = "单选题";
  631 + break;
  632 + case 3:
  633 + tit = "多选题";
  634 + break;
  635 + case 4:
  636 + tit = "判断题";
  637 + break;
  638 + case 5:
  639 + tit = "主观题";
  640 + break;
  641 + }
  642 + return tit;
  643 + },
  644 + edit(item) {
  645 + this.form = deepClone(item);
  646 + // this.form2 = deepClone(item);
  647 + // //组合每道大题中的相同题目
  648 + // let questionList = deepClone(item.questionList);
  649 + // for (let i = 0; i < questionList.length; i++) {
  650 + // let jsons = {};
  651 + // let answerOptions = [];
  652 + // questionList[i].subQuestions.map((items) => {
  653 + // let txt = this.setSubPro(items.questionType);
  654 + // if (jsons[txt]) {
  655 + // jsons[txt].push(items);
  656 + // } else {
  657 + // jsons[txt] = [items];
  658 + // }
  659 + // if (items.questionType == 2 || items.questionType == 3) {
  660 + // if (items.answerOptions.length > answerOptions.length) {
  661 + // answerOptions = items.answerOptions;
  662 + // }
  663 + // jsons[txt][0].answerOptions = answerOptions;
  664 + // }
  665 + // });
  666 + // this.form2.questionList[i].subQuestions = Object.keys(jsons).map(
  667 + // (item) => {
  668 + // return {
  669 + // name: item,
  670 + // list: jsons[item],
  671 + // answerList: "",
  672 + // };
  673 + // }
  674 + // );
  675 + // }
  676 + this.dialogVisible = true;
  677 + },
  678 + keydownAnswer(event) {//快速答案设置禁止输入
  679 + if (
  680 + event.key == "Meta" ||
  681 + event.key == "CapsLock" ||
  682 + event.key == "Shift" ||
  683 + event.key == "Enter" ||
  684 + event.key == "Alt" ||
  685 + event.key == "Backspace" ||
  686 + event.key == "Delete" ||
  687 + event.key == "ArrowUp" ||
  688 + event.key == "ArrowDown" ||
  689 + event.key == "ArrowLeft" ||
  690 + event.key == "v" ||
  691 + event.key == "V" ||
  692 + event.key == "ArrowRight"
  693 + ) {
  694 + return;
  695 + } else {
  696 + event.returnValue = "";
  697 + }
  698 + },
  699 + setAnswer(obj,answer){//多选答案设置
  700 + obj.answerList+=answer
  701 + let str = obj.answerList;
  702 + let str2 = checkAnswer(
  703 + str,
  704 + 3,
  705 + obj.list[0].answerOptions,
  706 + obj.list.length
  707 + );
  708 + obj.answerList = str2;
  709 + },
  710 + setDate(index) {
  711 + const that = this;
  712 + this.date = index == this.date ? "" : index;
  713 + that.query.day = "";
  714 + that.query.startDay = "";
  715 + that.query.endDay = "";
  716 + switch (index) {
  717 + case 1:
  718 + that.query.day = formatDate(new Date(), "yyyy-MM-dd");
  719 + that.query.startDay = that.query.day;
  720 + that.query.endDay = that.query.day;
  721 + break;
  722 + case 2: {
  723 + let times = new Date().getTime() - 24 * 60 * 60 * 1000;
  724 + that.query.day = formatDate(new Date(times), "yyyy-MM-dd");
  725 + that.query.startDay = that.query.day;
  726 + that.query.endDay = that.query.day;
  727 + break;
  728 + }
  729 + case 3: {
  730 + let day = new Date().getDay();
  731 + if (day == 0) {
  732 + //中国式星期天是一周的最后一天
  733 + day = 7;
  734 + }
  735 + let times1 = new Date().getTime() - 24 * 60 * 60 * 1000 * (day - 1);
  736 + let times2 = new Date().getTime() - 24 * 60 * 60 * 1000 * (day - 7);
  737 + that.query.startDay = formatDate(new Date(times1), "yyyy-MM-dd");
  738 + that.query.endDay = formatDate(new Date(times2), "yyyy-MM-dd");
  739 + break;
  740 + }
  741 + }
  742 + this.page = 1;
  743 + this._QueryData();
  744 + },
  745 + handleChangeTimeStart(val) {
  746 + this.query.day = "";
  747 + this.date = "";
  748 + if (this.query.endDay) {
  749 + if (new Date(val).getTime() > new Date(this.query.endDay).getTime()) {
  750 + this.$message.error("任务结束时间不能任务开始时间前面,请重新设置");
  751 + this.query.startDay = "";
  752 + }
  753 + }
  754 + },
  755 + handleChangeTimeEnd(val) {
  756 + this.query.day = "";
  757 + this.date = "";
  758 + if (this.query.startDay) {
  759 + if (new Date(val).getTime() < new Date(this.query.startDay).getTime()) {
  760 + this.$message.error("任务结束时间不能任务开始时间前面,请重新设置");
  761 + this.query.endDay = "";
  762 + }
  763 + }
  764 + },
  765 + changAnswer(sub, option) {
  766 + //设置多选答案
  767 + let str = new RegExp(option, "g");
  768 + if (sub.correctAnswer?.includes(option)) {
  769 + sub.correctAnswer = sub.correctAnswer.replace(str, "");
  770 + } else {
  771 + let arrs = (sub.correctAnswer && sub.correctAnswer.split("")) || [];
  772 + arrs.push(option);
  773 + sub.correctAnswer = arrs.sort().join("");
  774 + }
  775 + },
  776 + async saveAnswer(){
  777 + // const { data, code, message } = await this.$request.updateAnswerSheet({...this.form});
  778 + // if (code == 0) {
  779 + this.dialogVisible = false
  780 + // } else {
  781 + // this.$message.error(message);
  782 + // }
  783 + },
  784 + async changClazz() {
  785 + await this._QuerySubjectList();
  786 + await this.setDate(1);
  787 + },
  788 + async _QueryClassList() {
  789 + const { data, code, message } = await this.$request.fetchClassList();
  790 + if (code === 0) {
  791 + this.classList = data.list.map((item) => {
  792 + return {
  793 + value: item.clazzId,
  794 + label: item.clazzName,
  795 + };
  796 + });
  797 + this.query.clazzId = this.classList[0].value;
  798 + } else {
  799 + this.$message.error(message);
  800 + }
  801 + },
  802 + async _QuerySubjectList() {
  803 + const datas = this.query.clazzId
  804 + ? {
  805 + clazzId: this.query.clazzId,
  806 + }
  807 + : {};
  808 + const { data, code, message } = await this.$request.fetchSubjectList(
  809 + datas
  810 + );
  811 + if (code === 0) {
  812 + this.subjectList = data.list.map((item) => {
  813 + return {
  814 + value: item.subjectId,
  815 + label: item.subjectName,
  816 + };
  817 + });
  818 + if (this.role == "班主任") {
  819 + this.subjectList.unshift({
  820 + value: "",
  821 + label: "全部",
  822 + });
  823 + }
  824 + this.query.subjectId = this.subjectList[0].value;
  825 + } else {
  826 + this.$message.error(message);
  827 + }
  828 + },
  829 + async _QueryData() {
  830 + this.loading = true;
  831 + //多课时对比
  832 + let query = {};
  833 + for (let key in this.query) {
  834 + if (this.query[key] != "") {
  835 + query[key] = this.query[key];
  836 + }
  837 + }
  838 + const { data, code, message } = await this.$request.fetchQuizList({
  839 + ...query,
  840 + });
  841 + this.loading = false;
  842 + if (code === 0) {
  843 + } else {
  844 + this.$message.error(message);
  845 + }
  846 + },
  847 + },
  848 +};
12 </script> 849 </script>
13 850
14 -<style> 851 +<style lang="scss" scoped>
  852 +.table-box {
  853 + margin: 0 20px;
  854 + padding: 16px;
  855 + background: #f8f8f8;
  856 + border-radius: 5px;
  857 + :deep(.fa-arrow-right) {
  858 + padding-left: 2px;
  859 + }
  860 + :deep(.fa-file-text) {
  861 + padding-left: 2px;
  862 + }
  863 +}
15 864
  865 +.sub-questions {
  866 + width: 100%;
  867 + display: flex;
  868 + &:hover {
  869 + background: #f8f8f8;
  870 + }
  871 + & > div {
  872 + min-height: 40px;
  873 + padding: 5px;
  874 + flex-shrink: 0;
  875 + display: flex;
  876 + justify-content: center;
  877 + align-items: center;
  878 + }
  879 + .qs-num {
  880 + width: 80px;
  881 + font-size: 16px;
  882 + color: #333;
  883 + font-weight: 500;
  884 + }
  885 + .qs-options {
  886 + flex: 1;
  887 + }
  888 + .qs-options2 {
  889 + text-align: left;
  890 + justify-content: flex-start;
  891 + padding-left: 20px;
  892 + .answer-s {
  893 + cursor: pointer;
  894 + border-color: #667ffd;
  895 + color: #667ffd;
  896 + margin: 0 15px;
  897 + &.active {
  898 + color: #fff;
  899 + }
  900 + }
  901 + }
  902 + :deep(.el-select) {
  903 + .el-input__inner {
  904 + border-radius: 20px;
  905 + border-color: #667ffd;
  906 + width: 150px;
  907 + height: 32px;
  908 + line-height: 32px;
  909 + background: rgba($color: #667ffd, $alpha: 0.05);
  910 + }
  911 + .el-input__icon {
  912 + line-height: 32px;
  913 + }
  914 + }
  915 +}
  916 +.fa-exchange {
  917 + color: #667ffd;
  918 + cursor: pointer;
  919 + font-size: 16px;
  920 + margin-left: 10px;
  921 +}
  922 +.dia-btn {
  923 + border-radius: 20px;
  924 + margin: 0 20px;
  925 + padding: 10px 20px;
  926 +}
  927 +.dia-tips{
  928 + padding-bottom:10px;
  929 + }
  930 +.dia-question-box {
  931 + padding: 16px 16px 1px;
  932 + background: #f8f8f8;
  933 + border-radius: 10px;
  934 +
  935 + .answer-s {
  936 + width: 36px;
  937 + height: 28px;
  938 + cursor: pointer;
  939 + }
  940 +}
  941 +.set-questions {
  942 + display: flex;
  943 + margin-bottom: 12px;
  944 + width: 100%;
  945 + .qs-num {
  946 + flex-shrink: 0;
  947 + margin-right: 10px;
  948 + }
  949 + .qs-options {
  950 + flex: 1;
  951 + .ipt {
  952 + margin-bottom: 5px;
  953 + }
  954 + }
  955 + .delButton {
  956 + border-color: #ff6868;
  957 + background: #ff6868 url("../../assets/images/arrow.png") no-repeat center;
  958 + background-size: 19px;
  959 + color: transparent;
  960 + }
  961 + .ac{
  962 + border-color: #ff6868;
  963 + background: #ff6868;
  964 + color:#fff
  965 + }
  966 +}
  967 +.down{
  968 +padding-top:16px;
  969 +}
16 </style> 970 </style>
17 \ No newline at end of file 971 \ No newline at end of file
src/views/examinationPaper/detail.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <back-box>
  4 + <template slot="title">
  5 + <span>修改答案</span>
  6 + </template>
  7 + </back-box>
  8 + <div class="content">
  9 + <p class="tips">
  10 + <i class="fa fa-bell-o"></i> 2022-11-24 14:30张老师修改了答案。
  11 + </p>
  12 + <div class="answer-title">
  13 + <p class="name">{{ form.title }}</p>
  14 + <p class="totals">卷面总分:{{ allScore }}分</p>
  15 + </div>
  16 + <div v-for="(question, index) in form.questionList" :key="index">
  17 + <p class="question-title">
  18 + <span>{{ setBigNum(index) }}、</span>
  19 + <span class="title-txt">{{ question.questionTitle }}</span>
  20 + <span>共 {{ question.score }} 分</span>
  21 + </p>
  22 + <ul class="questions-ul">
  23 + <li class="sub-questions">
  24 + <div class="qs-num">题号</div>
  25 + <div class="qs-type">题型</div>
  26 + <div class="qs-score">分数</div>
  27 + <div class="qs-partScore">部分分值</div>
  28 + <div class="qs-answer">答案</div>
  29 + </li>
  30 + <li
  31 + class="sub-questions"
  32 + v-for="(subQuestions, indexs) in question.subQuestions"
  33 + :key="indexs"
  34 + >
  35 + <div class="qs-num">{{ subQuestions.questionIndex }}</div>
  36 + <div class="qs-type">
  37 + {{ setSubPro(subQuestions.questionType) }}
  38 + </div>
  39 + <div class="qs-score">
  40 + {{ subQuestions.score }}
  41 + </div>
  42 + <div class="qs-partScore">
  43 + {{ subQuestions.partScore }}
  44 + </div>
  45 + <div class="qs-answer">
  46 + {{ setAns(subQuestions.correctAnswer) }}
  47 + </div>
  48 + </li>
  49 + </ul>
  50 + </div>
  51 + <div class="btn-box">
  52 + <el-button type="danger" plain round @click="linkBack">取消</el-button>
  53 + <el-button type="primary" round @click="save">保存</el-button>
  54 + </div>
  55 + </div>
  56 + </div>
  57 +</template>
  58 +
  59 +<script>
  60 +export default {
  61 + methods: {
  62 + setSubPro(type) {
  63 + let tit;
  64 + switch (type) {
  65 + case 2:
  66 + tit = "单选题";
  67 + break;
  68 + case 3:
  69 + tit = "多选题";
  70 + break;
  71 + case 4:
  72 + tit = "判断题";
  73 + break;
  74 + case 5:
  75 + tit = "主观题";
  76 + break;
  77 + }
  78 + return tit;
  79 + },
  80 + setBigNum(num) {
  81 + let txt = "";
  82 + let bigNum = [
  83 + "一",
  84 + "二",
  85 + "三",
  86 + "四",
  87 + "五",
  88 + "六",
  89 + "七",
  90 + "八",
  91 + "九",
  92 + "十",
  93 + "十一",
  94 + "十二",
  95 + "十三",
  96 + "十四",
  97 + "十五",
  98 + "十六",
  99 + "十七",
  100 + "十八",
  101 + "十九",
  102 + "二十",
  103 + ];
  104 + txt = bigNum[num];
  105 +
  106 + return txt;
  107 + },
  108 + setAns(answer) {
  109 + let txt;
  110 + switch (answer) {
  111 + case 1:
  112 + case "1":
  113 + txt = "✓";
  114 + break;
  115 + case 2:
  116 + case "2":
  117 + txt = "✗";
  118 + break;
  119 + case "":
  120 + txt = "--";
  121 + break;
  122 + default:
  123 + txt = answer;
  124 + }
  125 + return txt
  126 + },
  127 + },
  128 +};
  129 +</script>
  130 +
  131 +<style lang="scss" scoped>
  132 +.content {
  133 + width: 100%;
  134 + box-sizing: border-box;
  135 + padding: 0 50px;
  136 + .ml-20 {
  137 + margin-left: 20px;
  138 + }
  139 + .btn-box {
  140 + text-align: right;
  141 + margin-left: 140px;
  142 + }
  143 + .tips {
  144 + height: 48px;
  145 + line-height: 48px;
  146 + padding: 0 16px;
  147 + border: 1px solid #fac7cc;
  148 + background-color: #ffebec;
  149 + font-size: 14px;
  150 + color: #fd9795;
  151 + margin: 10px 0 20px 0;
  152 + .fa-bell-o {
  153 + font-size: 18px;
  154 + margin-right: 5px;
  155 + }
  156 + }
  157 +}
  158 +.answer-title {
  159 + text-align: center;
  160 + font-size: 20px;
  161 + color: #333;
  162 + font-weight: 700;
  163 + padding-bottom: 20px;
  164 + .totals {
  165 + font-size: 16px;
  166 + color: #888;
  167 + font-weight: normal;
  168 + }
  169 +}
  170 +.question-title {
  171 + line-height: 40px;
  172 + .ipt {
  173 + width: 300px;
  174 + margin: 0 16px 0 10px;
  175 + :deep(.el-input__inner) {
  176 + border-radius: 20px;
  177 + border-color: #667ffd;
  178 + background: rgba($color: #667ffd, $alpha: 0.05);
  179 + }
  180 + }
  181 + .delete {
  182 + margin-right: 8px;
  183 + }
  184 + .title-txt {
  185 + margin-right: 20px;
  186 + font-size: 16px;
  187 + font-weight: 700;
  188 + }
  189 +}
  190 +</style>
0 \ No newline at end of file 191 \ No newline at end of file
src/views/examinationPaper/edit.vue
@@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
26 <ul class="questions-ul"> 26 <ul class="questions-ul">
27 <li class="sub-questions"> 27 <li class="sub-questions">
28 <div class="qs-num">题号</div> 28 <div class="qs-num">题号</div>
  29 + <div class="qs-type">题型</div>
29 <div class="qs-score">分数</div> 30 <div class="qs-score">分数</div>
30 <div class="qs-options qs-options2">选项设置</div> 31 <div class="qs-options qs-options2">选项设置</div>
31 </li> 32 </li>
@@ -245,7 +246,7 @@ export default { @@ -245,7 +246,7 @@ export default {
245 font-size: 20px; 246 font-size: 20px;
246 color: #333; 247 color: #333;
247 font-weight: 700; 248 font-weight: 700;
248 - padding: 20px 0 0 0; 249 + padding-bottom: 20px;
249 .totals { 250 .totals {
250 font-size: 16px; 251 font-size: 16px;
251 color: #888; 252 color: #888;
@@ -275,25 +276,7 @@ export default { @@ -275,25 +276,7 @@ export default {
275 .el-input-number { 276 .el-input-number {
276 width: 140px; 277 width: 140px;
277 } 278 }
278 -.answer-box {  
279 - .answer-s {  
280 - display: inline-block;  
281 - width: 30px;  
282 - height: 30px;  
283 - border: 1px solid #e2e2e2;  
284 - border-radius: 3px;  
285 - margin: 0 6px;  
286 - font-size: 16px;  
287 - color: #333;  
288 - text-align: center;  
289 - line-height: 30px;  
290 - &.active {  
291 - background: #5e78fa;  
292 - border-color: #5e78fa;  
293 - color: #fff;  
294 - }  
295 - }  
296 -} 279 +
297 .questions-ul { 280 .questions-ul {
298 border-left: 1px solid #e2e2e2; 281 border-left: 1px solid #e2e2e2;
299 border-top: 1px solid #e2e2e2; 282 border-top: 1px solid #e2e2e2;
src/views/examinationPaper/index.vue
@@ -19,20 +19,20 @@ @@ -19,20 +19,20 @@
19 19
20 <div class="answer-header"> 20 <div class="answer-header">
21 <div class="sel-box"> 21 <div class="sel-box">
22 - <el-select  
23 - class="sel"  
24 - v-model="query.clazzId"  
25 - placeholder="选择班级"  
26 - @change="changClazz" 22 + <el-cascader
  23 + class="sel sel2"
  24 + :options="options"
  25 + :props="props"
  26 + collapse-tags
  27 + clearable
  28 + placeholder="选择年级-班级"
  29 + v-model="query.gradeClass"
  30 + @change="changeGrade"
  31 + ><template slot-scope="{ node, data }">
  32 + <span>{{ data.label }}</span>
  33 + <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
  34 + </template></el-cascader
27 > 35 >
28 - <el-option  
29 - v-for="item in classList"  
30 - :key="item.value"  
31 - :label="item.label"  
32 - :value="item.value"  
33 - >{{ item.label }}  
34 - </el-option>  
35 - </el-select>  
36 <el-select 36 <el-select
37 class="sel" 37 class="sel"
38 v-model="query.subjectId" 38 v-model="query.subjectId"
@@ -134,10 +134,9 @@ @@ -134,10 +134,9 @@
134 icon="el-icon-more" 134 icon="el-icon-more"
135 ></el-button> 135 ></el-button>
136 <el-dropdown-menu slot="dropdown"> 136 <el-dropdown-menu slot="dropdown">
137 - <el-dropdown-item :command="1">授课端同步</el-dropdown-item>  
138 - <el-dropdown-item :command="2">修改分享范围</el-dropdown-item>  
139 - <el-dropdown-item :command="3">复制</el-dropdown-item>  
140 - <el-dropdown-item :command="4">归档</el-dropdown-item> 137 + <el-dropdown-item :command="1" v-if="this.$store.info.id == item.id">修改分享范围</el-dropdown-item>
  138 + <el-dropdown-item :command="2">复制</el-dropdown-item>
  139 + <el-dropdown-item :command="3">归档</el-dropdown-item>
141 </el-dropdown-menu> 140 </el-dropdown-menu>
142 </el-dropdown> 141 </el-dropdown>
143 </div> 142 </div>
@@ -170,9 +169,40 @@ export default { @@ -170,9 +169,40 @@ export default {
170 name: "examinationPaper", 169 name: "examinationPaper",
171 data() { 170 data() {
172 return { 171 return {
  172 + props: { multiple: true, checkStrictly: true },
  173 + options: [
  174 + {
  175 + value: 1,
  176 + label: "一年级",
  177 + children: [
  178 + {
  179 + value: 2,
  180 + label: "二班",
  181 + },
  182 + {
  183 + value: 3,
  184 + label: "三班",
  185 + },
  186 + ],
  187 + },
  188 + {
  189 + value: 4,
  190 + label: "二年级",
  191 + children: [
  192 + {
  193 + value: 5,
  194 + label: "二班",
  195 + },
  196 + {
  197 + value: 6,
  198 + label: "三班",
  199 + },
  200 + ],
  201 + },
  202 + ],
173 dialogVisible: false, 203 dialogVisible: false,
174 query: { 204 query: {
175 - clazzId: "2003", 205 + gradeClass: [],
176 subjectId: "0", 206 subjectId: "0",
177 typeName: "周测", 207 typeName: "周测",
178 title: "", 208 title: "",
@@ -202,9 +232,9 @@ export default { @@ -202,9 +232,9 @@ export default {
202 date: "2022-11-04 18:09:49", 232 date: "2022-11-04 18:09:49",
203 share: 1, 233 share: 1,
204 score: 100, 234 score: 100,
205 - gradeName:"二年级",  
206 - subjectId:1,  
207 - examsDuration:4800, 235 + gradeName: "二年级",
  236 + subjectId: 1,
  237 + examsDuration: 4800,
208 questionList: [ 238 questionList: [
209 { 239 {
210 questionTitle: "f", 240 questionTitle: "f",
@@ -234,9 +264,9 @@ export default { @@ -234,9 +264,9 @@ export default {
234 date: "2022-11-04 18:09:49", 264 date: "2022-11-04 18:09:49",
235 share: 1, 265 share: 1,
236 score: 100, 266 score: 100,
237 - gradeName:"二年级",  
238 - subjectId:1,  
239 - examsDuration:3000, 267 + gradeName: "二年级",
  268 + subjectId: 1,
  269 + examsDuration: 3000,
240 questionList: [ 270 questionList: [
241 { 271 {
242 questionTitle: "f", 272 questionTitle: "f",
@@ -287,38 +317,22 @@ export default { @@ -287,38 +317,22 @@ export default {
287 const that = this; 317 const that = this;
288 switch (value) { 318 switch (value) {
289 case 1: 319 case 1:
290 - //授课端同步  
291 - that.syncMeg(item);  
292 - break;  
293 - case 2:  
294 //修改分享范围 320 //修改分享范围
295 that.shareForm.id = item.id; 321 that.shareForm.id = item.id;
296 that.shareForm.grade = item.grade; 322 that.shareForm.grade = item.grade;
297 that.shareForm.share = item.share || 1; 323 that.shareForm.share = item.share || 1;
298 that.dialogVisible = true; 324 that.dialogVisible = true;
299 break; 325 break;
300 - case 3: 326 + case 2:
301 //复制 327 //复制
302 - that.toAdd({ type: 2, form: JSON.stringify(item), }); 328 + that.toAdd({ type: 2, form: JSON.stringify(item) });
303 break; 329 break;
304 - case 4: 330 + case 3:
305 //归档 331 //归档
306 that.recovery(item); 332 that.recovery(item);
307 break; 333 break;
308 } 334 }
309 }, 335 },
310 - async syncMeg() {  
311 - //同步  
312 - // const { data, code, message } = await this.$request.fetchAnswerList({  
313 - // ...this.shareForm,  
314 - // });  
315 - // this.loading = false;  
316 - // if (code === 0) {  
317 - this.$message.success("已同步");  
318 - // } else {  
319 - // this.$message.error(message);  
320 - // }  
321 - },  
322 async saveShare() { 336 async saveShare() {
323 //修改分享范围 337 //修改分享范围
324 // const { data, code, message } = await this.$request.fetchAnswerList({ 338 // const { data, code, message } = await this.$request.fetchAnswerList({
@@ -347,12 +361,12 @@ export default { @@ -347,12 +361,12 @@ export default {
347 // this.$message.error(message); 361 // this.$message.error(message);
348 // } 362 // }
349 }, 363 },
350 -  
351 - async changClazz() { 364 + async changeGrade() {
352 //切换班级 365 //切换班级
353 await this._QuerySubjectList(); 366 await this._QuerySubjectList();
354 this._QueryData(); 367 this._QueryData();
355 }, 368 },
  369 + async changClazz() {},
356 // 查找答题卡类型 370 // 查找答题卡类型
357 async _QueryTypeList() { 371 async _QueryTypeList() {
358 const { data, code, message } = await this.$request.fetchTypeNames(); 372 const { data, code, message } = await this.$request.fetchTypeNames();
@@ -534,6 +548,16 @@ export default { @@ -534,6 +548,16 @@ export default {
534 } 548 }
535 } 549 }
536 } 550 }
  551 +.answer-header {
  552 + .sel-box {
  553 + .sel {
  554 + min-width: 160px;
  555 + }
  556 + :deep(.el-cascader__tags) {
  557 + flex-wrap: nowrap;
  558 + }
  559 + }
  560 +}
537 .dialog-footer { 561 .dialog-footer {
538 text-align: center; 562 text-align: center;
539 :deep(.el-button) { 563 :deep(.el-button) {
src/views/examinationPaper/recycle.vue
@@ -7,50 +7,51 @@ @@ -7,50 +7,51 @@
7 </back-box> 7 </back-box>
8 <div class="answer-header"> 8 <div class="answer-header">
9 <div class="sel-box"> 9 <div class="sel-box">
10 - <el-select  
11 - class="sel"  
12 - v-model="query.gradeName"  
13 - placeholder="" 10 + <el-cascader
  11 + class="sel sel2"
  12 + :options="options"
  13 + :props="props"
  14 + collapse-tags
  15 + clearable
  16 + placeholder="选择年级-班级"
  17 + v-model="query.gradeClass"
14 @change="changeGrade" 18 @change="changeGrade"
  19 + ><template slot-scope="{ node, data }">
  20 + <span>{{ data.label }}</span>
  21 + <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
  22 + </template></el-cascader
15 > 23 >
16 - <el-option  
17 - v-for="item in gradeList"  
18 - :key="item"  
19 - :label="item"  
20 - :value="item"  
21 - >  
22 - </el-option>  
23 - </el-select>  
24 <el-select 24 <el-select
25 class="sel" 25 class="sel"
26 - v-model="query.type"  
27 - placeholder="选择类型" 26 + v-model="query.subjectId"
  27 + placeholder="选择科目"
28 @change="_QueryData()" 28 @change="_QueryData()"
29 > 29 >
30 <el-option label="全部" value=""></el-option> 30 <el-option label="全部" value=""></el-option>
31 <el-option 31 <el-option
32 - v-for="item in typeList" 32 + v-for="item in subjectList"
33 :key="item.value" 33 :key="item.value"
34 :label="item.label" 34 :label="item.label"
35 :value="item.value" 35 :value="item.value"
36 - >{{ item.label }} 36 + >
37 </el-option> 37 </el-option>
38 </el-select> 38 </el-select>
39 <el-select 39 <el-select
40 class="sel" 40 class="sel"
41 - v-model="query.subjectId"  
42 - placeholder="选择科目" 41 + v-model="query.type"
  42 + placeholder="选择类型"
43 @change="_QueryData()" 43 @change="_QueryData()"
44 > 44 >
45 <el-option label="全部" value=""></el-option> 45 <el-option label="全部" value=""></el-option>
46 <el-option 46 <el-option
47 - v-for="item in subjectList" 47 + v-for="item in typeList"
48 :key="item.value" 48 :key="item.value"
49 :label="item.label" 49 :label="item.label"
50 :value="item.value" 50 :value="item.value"
51 - > 51 + >{{ item.label }}
52 </el-option> 52 </el-option>
53 </el-select> 53 </el-select>
  54 +
54 <el-input 55 <el-input
55 placeholder="输入试卷名称" 56 placeholder="输入试卷名称"
56 v-model="query.title" 57 v-model="query.title"
@@ -89,7 +90,7 @@ @@ -89,7 +90,7 @@
89 </p> 90 </p>
90 </div> 91 </div>
91 <div class="btn-box"> 92 <div class="btn-box">
92 - <el-tooltip effect="dark" content="使用" placement="bottom"> 93 + <el-tooltip effect="dark" content="恢复" placement="bottom">
93 <el-button 94 <el-button
94 class="edit" 95 class="edit"
95 type="info" 96 type="info"
@@ -119,16 +120,47 @@ @@ -119,16 +120,47 @@
119 export default { 120 export default {
120 data() { 121 data() {
121 return { 122 return {
  123 + props: { multiple: true, checkStrictly: true },
  124 + options: [
  125 + {
  126 + value: 1,
  127 + label: "一年级",
  128 + children: [
  129 + {
  130 + value: 2,
  131 + label: "二班",
  132 + },
  133 + {
  134 + value: 3,
  135 + label: "三班",
  136 + },
  137 + ],
  138 + },
  139 + {
  140 + value: 4,
  141 + label: "二年级",
  142 + children: [
  143 + {
  144 + value: 5,
  145 + label: "二班",
  146 + },
  147 + {
  148 + value: 6,
  149 + label: "三班",
  150 + },
  151 + ],
  152 + },
  153 + ],
122 query: { 154 query: {
123 - gradeName: "二年级", 155 + gradeClass: [],
124 type: "", 156 type: "",
125 subjectId: "", 157 subjectId: "",
126 title: "", 158 title: "",
127 }, 159 },
128 gradeList: ["二年级"], 160 gradeList: ["二年级"],
129 typeList: [ 161 typeList: [
130 - { label: "随堂问", value: 1 },  
131 - { label: "即使测", value: 2 }, 162 + { label: "周测", value: 1 },
  163 + { label: "月测", value: 2 },
132 ], 164 ],
133 subjectList: [], 165 subjectList: [],
134 tableData: [ 166 tableData: [
@@ -165,9 +197,9 @@ export default { @@ -165,9 +197,9 @@ export default {
165 //删除答题卡 197 //删除答题卡
166 // const { data, code, message } = await this.$request.useAnswerSheet(); 198 // const { data, code, message } = await this.$request.useAnswerSheet();
167 // if (code == 0) { 199 // if (code == 0) {
168 - this.tableData = this.tableData.filter(item=>{  
169 - return obj.if != item.id  
170 - }) 200 + this.tableData = this.tableData.filter((item) => {
  201 + return obj.if != item.id;
  202 + });
171 // } else { 203 // } else {
172 // this.$message.error(message); 204 // this.$message.error(message);
173 // } 205 // }
@@ -176,9 +208,9 @@ export default { @@ -176,9 +208,9 @@ export default {
176 //删除答题卡 208 //删除答题卡
177 // const { data, code, message } = await this.$request.removeAnswerSheet(); 209 // const { data, code, message } = await this.$request.removeAnswerSheet();
178 // if (code == 0) { 210 // if (code == 0) {
179 - this.tableData = this.tableData.filter(item=>{  
180 - return obj.if != item.id  
181 - }) 211 + this.tableData = this.tableData.filter((item) => {
  212 + return obj.if != item.id;
  213 + });
182 // } else { 214 // } else {
183 // this.$message.error(message); 215 // this.$message.error(message);
184 // } 216 // }
@@ -211,10 +243,19 @@ export default { @@ -211,10 +243,19 @@ export default {
211 this.$message.error(message); 243 this.$message.error(message);
212 } 244 }
213 }, 245 },
  246 + // 查找答题卡类型
  247 + async _QueryTypeList() {
  248 + const { data, code, message } = await this.$request.fetchTypeNames();
  249 + if (code === 0) {
  250 + this.typeList = [...data.typeNames] || [];
  251 + } else {
  252 + this.$message.error(message);
  253 + }
  254 + },
214 async changeGrade() { 255 async changeGrade() {
215 - this._QueryData();  
216 - this._GradeList();  
217 - this._QuerySubjectList(); 256 + // this._QueryData();
  257 + // this._GradeList();
  258 + // this._QuerySubjectList();
218 }, 259 },
219 async _GradeList() { 260 async _GradeList() {
220 //查询年级列表 261 //查询年级列表
@@ -257,6 +298,9 @@ export default { @@ -257,6 +298,9 @@ export default {
257 .sel { 298 .sel {
258 min-width: 160px; 299 min-width: 160px;
259 } 300 }
  301 + :deep(.el-cascader__tags) {
  302 + flex-wrap: nowrap;
  303 + }
260 } 304 }
261 } 305 }
262 .content { 306 .content {
src/views/index/mainIndex.vue
1 <template> 1 <template>
2 <div class="container"> 2 <div class="container">
3 <ul class="nav-list" v-if="type == '学校管理员'"> 3 <ul class="nav-list" v-if="type == '学校管理员'">
4 - <li class="nav-item item1" @click="links('setUpAccount')"> 4 + <li class="nav-item item1" @click="links('/setUpAccount')">
5 <img class="icon" src="../../assets/nav/setUpAccount.png" alt="" /> 5 <img class="icon" src="../../assets/nav/setUpAccount.png" alt="" />
6 <div class="text"> 6 <div class="text">
7 <p class="p1">账号管理</p> 7 <p class="p1">账号管理</p>
8 <p class="p2">管理32个任课教师,14个班主任,3个备课组长账号信息。</p> 8 <p class="p2">管理32个任课教师,14个班主任,3个备课组长账号信息。</p>
9 </div> 9 </div>
10 </li> 10 </li>
11 - <li class="nav-item item1" @click="links('setUpSchool')"> 11 + <li class="nav-item item1" @click="links('/setUpSchool')">
12 <img class="icon" src="../../assets/nav/setUpSchool.png" alt="" /> 12 <img class="icon" src="../../assets/nav/setUpSchool.png" alt="" />
13 <div class="text"> 13 <div class="text">
14 <p class="p1">学校管理</p> 14 <p class="p1">学校管理</p>
15 <p class="p2">管理6个年级,3个班级,397名学生信息。</p> 15 <p class="p2">管理6个年级,3个班级,397名学生信息。</p>
16 </div> 16 </div>
17 </li> 17 </li>
18 - <li class="nav-item item2" @click="links('device')"> 18 + <li class="nav-item item2" @click="links('/device')">
19 <img class="icon" src="../../assets/nav/device.png" alt="" /> 19 <img class="icon" src="../../assets/nav/device.png" alt="" />
20 <div class="text"> 20 <div class="text">
21 <p class="p1">设备状态</p> 21 <p class="p1">设备状态</p>
@@ -23,66 +23,70 @@ @@ -23,66 +23,70 @@
23 </div> 23 </div>
24 </li> 24 </li>
25 <li class="item3"> 25 <li class="item3">
26 - <div class="nav-item item1 item-child1" @click="links('analysis')"> 26 + <div class="nav-item item1 item-child1" @click="links('/analysis')">
27 <img class="icon" src="../../assets/nav/analysis.png" alt="" /> 27 <img class="icon" src="../../assets/nav/analysis.png" alt="" />
28 <div class="text"> 28 <div class="text">
29 <p class="p1">使用分析</p> 29 <p class="p1">使用分析</p>
30 <p class="p2">按班级、科目等维度分析设备使用频率。</p> 30 <p class="p2">按班级、科目等维度分析设备使用频率。</p>
31 </div> 31 </div>
32 </div> 32 </div>
33 - <div class="nav-item item1 item-child2" @click="links('card')"> 33 + <div class="nav-item item1 item-child2" @click="links('/card')">
34 <img class="icon" src="../../assets/nav/card.png" alt="" /> 34 <img class="icon" src="../../assets/nav/card.png" alt="" />
35 <p class="p1">发卡补卡</p> 35 <p class="p1">发卡补卡</p>
36 <p class="p2">为学生办理发卡、补卡业务。</p> 36 <p class="p2">为学生办理发卡、补卡业务。</p>
37 </div> 37 </div>
38 - <div class="nav-item item1 item-child2" @click="links('down')"> 38 + <div class="nav-item item1 item-child2" @click="links('/down')">
39 <img class="icon" src="../../assets/nav/down.png" alt="" /> 39 <img class="icon" src="../../assets/nav/down.png" alt="" />
40 <p class="p1">软件下载</p> 40 <p class="p1">软件下载</p>
41 <p class="p2">设置参数,下载授课端软件。</p> 41 <p class="p2">设置参数,下载授课端软件。</p>
42 </div> 42 </div>
43 </li> 43 </li>
44 </ul> 44 </ul>
45 - <ul class="nav-list" v-if="type == '集团管理员'">  
46 - <li v-for="item in navList" :key="item.path" class="nav-item item4" @click="links(item.path)"> 45 + <ul class="nav-list" v-if="type == 'ROLE_JITUAN'">
  46 + <template v-for="item in navList">
  47 + <li v-if="item.path!='dataSync'" :key="item.path" class="nav-item item4" @click="links(item.path)">
47 <img class="icon" :src="getImgs(item.path)" alt="" /> 48 <img class="icon" :src="getImgs(item.path)" alt="" />
48 - <div class="text" v-if="item.path == 'setUpConglomerate'"> 49 + <div class="text" v-if="item.path == '/setUpConglomerate'">
49 <p class="p1">学校管理</p> 50 <p class="p1">学校管理</p>
50 <p class="p2">管理3个区域,14个学校。</p> 51 <p class="p2">管理3个区域,14个学校。</p>
51 </div> 52 </div>
52 - <div class="text" v-else-if="item.path == 'setUpAccount'"> 53 + <div class="text" v-else-if="item.path == '/setUpAccount'">
53 <p class="p1">账号管理</p> 54 <p class="p1">账号管理</p>
54 <p class="p2">共35个各层级管理员账号。</p> 55 <p class="p2">共35个各层级管理员账号。</p>
55 </div> 56 </div>
56 - <div class="text" v-else-if="item.path == 'device'"> 57 + <div class="text" v-else-if="item.path == '/device'">
57 <p class="p1">设备状态</p> 58 <p class="p1">设备状态</p>
58 <p class="p2">管理14个基站,396套答题器设备。</p> 59 <p class="p2">管理14个基站,396套答题器设备。</p>
59 </div> 60 </div>
60 - <div class="text" v-else> 61 + <div class="text" v-else-if="item.path == '/analysis'">
61 <p class="p1">使用分析</p> 62 <p class="p1">使用分析</p>
62 <p class="p2">按软件功能、题型统计使用频率。</p> 63 <p class="p2">按软件功能、题型统计使用频率。</p>
63 </div> 64 </div>
64 </li> 65 </li>
  66 + </template>
65 </ul> 67 </ul>
66 - <ul class="nav-list" v-if="type == '班主任' || type == '任课老师' ">  
67 - <li v-for="item in navList" :key="item.path" class="nav-item item4" @click="links(item.path)"> 68 + <ul class="nav-list" v-if="type == 'superAdmin' || type == '任课老师' ">
  69 + <template v-for="item in navList">
  70 + <li v-if="item.path!='dataSync'" :key="item.path" class="nav-item item4" @click="links(item.path)">
68 <img class="icon" :src="getImgs(item.path)" alt="" /> 71 <img class="icon" :src="getImgs(item.path)" alt="" />
69 - <div class="text" v-if="item.path == 'examinationPaper'"> 72 + <div class="text" v-if="item.path == '/examinationPaper'">
70 <p class="p1">备题组卷</p> 73 <p class="p1">备题组卷</p>
71 <p class="p2">管理32套答题卡。</p> 74 <p class="p2">管理32套答题卡。</p>
72 </div> 75 </div>
73 - <div class="text" v-else-if="item.path == 'portrait'"> 76 + <div class="text" v-else-if="item.path == '/portrait'">
74 <p class="p1">学生画像</p> 77 <p class="p1">学生画像</p>
75 <p class="p2">共分析532名学生成绩。</p> 78 <p class="p2">共分析532名学生成绩。</p>
76 </div> 79 </div>
77 - <div class="text" v-else-if="item.path == 'ask'"> 80 + <div class="text" v-else-if="item.path == '/ask'">
78 <p class="p1">随堂问报表</p> 81 <p class="p1">随堂问报表</p>
79 <p class="p2">对41套随堂问答题记录分析。</p> 82 <p class="p2">对41套随堂问答题记录分析。</p>
80 </div> 83 </div>
81 - <div class="text" v-else> 84 + <div class="text" v-else-if="item.path == '/test'">
82 <p class="p1">即时测报表</p> 85 <p class="p1">即时测报表</p>
83 <p class="p2">对28套即时测答题记录分析。</p> 86 <p class="p2">对28套即时测答题记录分析。</p>
84 </div> 87 </div>
85 </li> 88 </li>
  89 + </template>
86 </ul> 90 </ul>
87 </div> 91 </div>
88 </template> 92 </template>
@@ -92,54 +96,26 @@ export default { @@ -92,54 +96,26 @@ export default {
92 name: "mainIndex", 96 name: "mainIndex",
93 data() { 97 data() {
94 return { 98 return {
95 - // type: "学校管理员",  
96 - // type: "集团管理员",  
97 - // type: "班主任",  
98 - type: "任课老师",  
99 - navList: [  
100 - // {  
101 - // name: "学校管理",  
102 - // path: "setUpConglomerate",  
103 - // },  
104 - // {  
105 - // name: "账号管理",  
106 - // path: "setUpAccount",  
107 - // },  
108 - // {  
109 - // name: "设备状态",  
110 - // path: "device",  
111 - // },  
112 - // {  
113 - // name: "使用分析",  
114 - // path: "analysis",  
115 - // },  
116 - {  
117 - name: "备题组卷",  
118 - path: "examinationPaper",  
119 - },  
120 - {  
121 - name: "学生画像",  
122 - path: "portrait",  
123 - },  
124 - {  
125 - name: "随堂问报表",  
126 - path: "ask",  
127 - },  
128 - {  
129 - name: "即时测报表",  
130 - path: "test",  
131 - },  
132 - ], 99 + type: "",
  100 + navList: [],
133 }; 101 };
134 }, 102 },
135 - mounted() {}, 103 + created() {
  104 + this.type = this.$store.getters.info.permissions[0].role
  105 + this.navList = this.$store.getters.addRouters.map(item=>{
  106 + return {
  107 + name:item.name,
  108 + path:item.children[0].path,
  109 + }
  110 + })
  111 + },
136 methods: { 112 methods: {
137 getImgs(path) { 113 getImgs(path) {
138 - return require(`@/assets/nav/${path}.png`) 114 + return require(`@/assets/nav${path}.png`)
139 }, 115 },
140 links(path) { 116 links(path) {
141 this.$router.push({ 117 this.$router.push({
142 - path: `/${path}`, 118 + path: path,
143 }); 119 });
144 }, 120 },
145 }, 121 },
src/views/layout/aside/aside.vue
1 <template> 1 <template>
2 - <div> 2 + <div class="aside-box">
3 <el-aside id="asideNav"> 3 <el-aside id="asideNav">
4 <div class="logo-name"> 4 <div class="logo-name">
5 <img 5 <img
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 /> 10 />
11 <template v-else> 11 <template v-else>
12 <img class="logo" src="../../../assets/images/logo.png" alt="" /> 12 <img class="logo" src="../../../assets/images/logo.png" alt="" />
13 - <p>中天易教</p> 13 + <p class="ellipsis">中天易教中天易教中天易教</p>
14 </template> 14 </template>
15 </div> 15 </div>
16 <el-menu 16 <el-menu
@@ -116,7 +116,9 @@ $right: right; @@ -116,7 +116,9 @@ $right: right;
116 #{$side}-#{$prop}: $value; 116 #{$side}-#{$prop}: $value;
117 } 117 }
118 } 118 }
119 - 119 +.aside-box{
  120 + max-width:200px;
  121 +}
120 #asideNav { 122 #asideNav {
121 width: auto !important; 123 width: auto !important;
122 display: flex; 124 display: flex;
@@ -135,7 +137,8 @@ $right: right; @@ -135,7 +137,8 @@ $right: right;
135 height: 24px; 137 height: 24px;
136 margin-right: 10px; 138 margin-right: 10px;
137 } 139 }
138 - p { 140 + .ellipsis {
  141 + overflow: hidden;
139 line-height: 50px; 142 line-height: 50px;
140 text-align: center; 143 text-align: center;
141 font-size: 16px; 144 font-size: 16px;
src/views/layout/layout.vue
@@ -38,13 +38,16 @@ export default { @@ -38,13 +38,16 @@ export default {
38 }; 38 };
39 }, 39 },
40 created() { 40 created() {
41 - this.code = getURLParams("code") || "";  
42 - if (this.code) {  
43 - localStorage.setItem("code",this.code)  
44 - this._LoginCheck();  
45 - } 41 + this.initRouter();
46 }, 42 },
47 methods: { 43 methods: {
  44 + initRouter() {
  45 + this.code = getURLParams("code") || this.$store.getters.code;
  46 + if (this.code) {
  47 + this.$store.commit("setCode", this.code);
  48 + this._LoginCheck();
  49 + }
  50 + },
48 async _LoginCheck() { 51 async _LoginCheck() {
49 let params = {}; 52 let params = {};
50 if (this.code) { 53 if (this.code) {
@@ -52,17 +55,46 @@ export default { @@ -52,17 +55,46 @@ export default {
52 code: this.code, 55 code: this.code,
53 }; 56 };
54 } 57 }
55 - const { data = {}, message, code } = await loginCheck(params);  
56 - if (code === 0) {  
57 - if (data) {  
58 - this.school = data.schoolName;  
59 - this.user.name = data.realName;  
60 - this.user.id = data.id;  
61 - this.user.tx = data.smallHeaderImgPath;  
62 - }  
63 - } else {  
64 - this.$message.error(message);  
65 - } 58 + // const { data = {}, message, code } = await loginCheck(params);
  59 + // if (code === 0) {
  60 + // if (data) {
  61 + const userInfo = {
  62 + permissions: [
  63 + {
  64 + role: "superAdmin",
  65 + roleName: "超级管理员",
  66 + },
  67 + ],
  68 + name: "李老师",
  69 + // avatar: data.avatar ? data.avatar : "",
  70 + // uid: data.id,
  71 + authorityRouter: [
  72 + "examinationPaper",
  73 + "examinationPaperAdd",
  74 + "examinationPaperEdit",
  75 + "examinationPaperRecycle",
  76 + "ask",
  77 + "askAnalysis",
  78 + "test",
  79 + "testAnalysis",
  80 + ],
  81 + };
  82 + await this.$store.commit("setInfo", { ...userInfo });
  83 + await this.$store.commit("setRouters", userInfo.authorityRouter);
  84 + let newAddRouters = this.$store.getters.addRouters;
  85 + newAddRouters.forEach((res) => {
  86 + this.$router.addRoute(res);
  87 + });
  88 + this.$router.addRoute({
  89 + path: "*",
  90 + redirect: "/404",
  91 + hidden: true,
  92 + children: [],
  93 + });
  94 + // }
  95 + // } else {
  96 + // this.$message.error(message);
  97 + // }
66 }, 98 },
67 }, 99 },
68 }; 100 };
src/views/login/index.vue
@@ -90,8 +90,8 @@ export default { @@ -90,8 +90,8 @@ export default {
90 disableClick: true, 90 disableClick: true,
91 passwordType: "password", 91 passwordType: "password",
92 loginForm: { 92 loginForm: {
93 - username: "admin",  
94 - password: "123456", 93 + username: "15911715665",
  94 + password: "Csiy88888",
95 }, 95 },
96 loginRules: { 96 loginRules: {
97 username: [ 97 username: [
vue.config.js
@@ -12,7 +12,7 @@ module.exports = { @@ -12,7 +12,7 @@ module.exports = {
12 productionSourceMap: false, // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 12 productionSourceMap: false, // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
13 devServer: { 13 devServer: {
14 hot:true, 14 hot:true,
15 - port: 8080, // 端口 15 + port: 8081, // 端口
16 open: false, // 启动后打开浏览器 16 open: false, // 启动后打开浏览器
17 compress: true, 17 compress: true,
18 overlay: { 18 overlay: {
@@ -20,13 +20,13 @@ module.exports = { @@ -20,13 +20,13 @@ module.exports = {
20 warnings: false, 20 warnings: false,
21 errors: true, 21 errors: true,
22 }, 22 },
23 - proxy: {  
24 - "/": {  
25 - target:"http://lead.xc.com:32269",  
26 - changeOrigin: true,  
27 - ws:true,  
28 - },  
29 - }, 23 + // proxy: {
  24 + // "/": {
  25 + // target:"http://192.168.3.29:8080",
  26 + // changeOrigin: true,
  27 + // ws:true,
  28 + // },
  29 + // },
30 disableHostCheck: true 30 disableHostCheck: true
31 }, 31 },
32 css: { 32 css: {