重构完成

UI_2022-02-10
yujialong 4 years ago
commit 84a84efaed
  1. 3
      .browserslistrc
  2. 22
      .gitignore
  3. 6
      .prettierrc
  4. 21
      LICENSE
  5. 5
      babel.config.js
  6. 13615
      package-lock.json
  7. 40
      package.json
  8. 5
      postcss.config.js
  9. 18
      public/index.html
  10. 24
      src/App.vue
  11. 158
      src/api/index.js
  12. BIN
      src/assets/img/05学生-练习记录_03.png
  13. BIN
      src/assets/img/05学生-练习记录_05.png
  14. BIN
      src/assets/img/17查看成绩1.png
  15. BIN
      src/assets/img/17查看成绩2.png
  16. BIN
      src/assets/img/17查看成绩3.png
  17. BIN
      src/assets/img/17查看成绩4.png
  18. BIN
      src/assets/img/17查看成绩5.png
  19. BIN
      src/assets/img/17查看成绩6.png
  20. BIN
      src/assets/img/17查看成绩7.png
  21. BIN
      src/assets/img/3.png
  22. BIN
      src/assets/img/back.png
  23. BIN
      src/assets/img/bg_1.png
  24. BIN
      src/assets/img/bg_2.png
  25. BIN
      src/assets/img/bind.png
  26. BIN
      src/assets/img/cup.png
  27. BIN
      src/assets/img/date.png
  28. BIN
      src/assets/img/edit.png
  29. BIN
      src/assets/img/evaluation_bg1.png
  30. BIN
      src/assets/img/evaluation_bg2.png
  31. BIN
      src/assets/img/evaluation_bg3.png
  32. BIN
      src/assets/img/false.png
  33. BIN
      src/assets/img/get.png
  34. BIN
      src/assets/img/hourglass.png
  35. BIN
      src/assets/img/icon-weigouxuan.png
  36. BIN
      src/assets/img/icon-xiangyou.png
  37. BIN
      src/assets/img/icon-yigouxuan.png
  38. BIN
      src/assets/img/icon_1.png
  39. BIN
      src/assets/img/icon_2.png
  40. BIN
      src/assets/img/icon_qq.png
  41. BIN
      src/assets/img/icon_wechat.png
  42. BIN
      src/assets/img/idcard.png
  43. BIN
      src/assets/img/img.jpg
  44. BIN
      src/assets/img/login_icon_close.png
  45. BIN
      src/assets/img/logo-hh.png
  46. BIN
      src/assets/img/logo-hh1.png
  47. BIN
      src/assets/img/logo.png
  48. BIN
      src/assets/img/open.png
  49. BIN
      src/assets/img/person/bg.png
  50. BIN
      src/assets/img/person/manag.png
  51. BIN
      src/assets/img/person/user.png
  52. BIN
      src/assets/img/ques1.png
  53. BIN
      src/assets/img/school.png
  54. BIN
      src/assets/img/select.png
  55. BIN
      src/assets/img/station1.png
  56. BIN
      src/assets/img/station10.png
  57. BIN
      src/assets/img/station11.png
  58. BIN
      src/assets/img/station12.png
  59. BIN
      src/assets/img/station2.png
  60. BIN
      src/assets/img/station3.png
  61. BIN
      src/assets/img/station4.png
  62. BIN
      src/assets/img/station5.png
  63. BIN
      src/assets/img/station6.png
  64. BIN
      src/assets/img/station7.png
  65. BIN
      src/assets/img/station8.png
  66. BIN
      src/assets/img/station9.png
  67. BIN
      src/assets/img/student1.png
  68. BIN
      src/assets/img/student2.png
  69. BIN
      src/assets/img/student3.png
  70. BIN
      src/assets/img/student4.png
  71. BIN
      src/assets/img/true.png
  72. 124
      src/components/pdf/index.vue
  73. 179
      src/components/quill/index.vue
  74. 16
      src/components/quill/options.js
  75. 30
      src/i18n/index.js
  76. 43
      src/layouts/footer/index.vue
  77. 121
      src/layouts/header/index.vue
  78. 69
      src/layouts/home/index.vue
  79. 69
      src/layouts/navbar/index.vue
  80. 25
      src/libs/auth/generateBtnPermission.js
  81. 6
      src/libs/bus.js
  82. 10
      src/libs/random_str.js
  83. 16
      src/libs/resize/index.js
  84. 32
      src/libs/route/addRoutes.js
  85. 26
      src/libs/route/generateRoutes.js
  86. 6
      src/libs/route/resetRouter.js
  87. 43
      src/libs/util.cookies.js
  88. 83
      src/libs/util.db.js
  89. 159
      src/libs/util.js
  90. 45
      src/main.js
  91. 11
      src/mixins/app.js
  92. 8
      src/mixins/setBackground/index.js
  93. 574
      src/pages/account/login/index.vue
  94. 237
      src/pages/account/register/index.vue
  95. 369
      src/pages/ass/list/index.vue
  96. 59
      src/pages/exception/error/403/index.vue
  97. 59
      src/pages/exception/error/404/index.vue
  98. 46
      src/pages/exception/i18n/index.vue
  99. 225
      src/pages/exception/icon/index.vue
  100. 31
      src/pages/index/list/index.vue
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,3 @@
> 1%
last 2 versions
not ie <= 8

22
.gitignore vendored

@ -0,0 +1,22 @@
.DS_Store
node_modules
/dist
example.html
favicon.ico
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

@ -0,0 +1,6 @@
{
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 140
}

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016-2019 vue-manage-system
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}

13615
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,40 @@
{
"name": "vue-manage-system",
"version": "4.2.0",
"private": true,
"scripts": {
"dev": "npm run serve",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",
"echarts": "^4.8.0",
"element-theme": "^2.0.1",
"element-ui": "^2.13.0",
"html2canvas": "^1.2.1",
"js-cookie": "^2.2.1",
"jspdf": "^2.3.1",
"mavon-editor": "^2.6.17",
"postcss-px2rem": "^0.3.0",
"px2rem-loader": "^0.1.9",
"vue": "^2.6.10",
"vue-cropperjs": "^3.0.0",
"vue-i18n": "^8.10.0",
"vue-pdf": "^4.2.0",
"vue-quill-editor": "^3.0.6",
"vue-router": "^3.0.3",
"vue-schart": "^2.0.0",
"vuedraggable": "^2.17.0",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.9.0",
"@vue/cli-service": "^3.9.0",
"element-theme-chalk": "^2.13.0",
"node-sass": "^4.13.0",
"sass-loader": "^8.0.0",
"vue-template-compiler": "^2.6.10"
}
}

@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<link rel="stylesheet" href="//at.alicdn.com/t/font_830376_qzecyukz0s.css">
<title>职站</title>
</head>
<body>
<noscript>
<strong>We're sorry but vms doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,24 @@
<template>
<div id="app" >
<router-view></router-view>
</div>
</template>
<script>
import Setting from '@/setting';
import util from '@/libs/util';
export default {
name: 'App',
created () {
//localStorage
if (util.local.get(Setting.storeKey) ) {
this.$store.replaceState(Object.assign({}, this.$store.state,util.local.get(Setting.storeKey)))
}
//vuexlocalStorage
window.addEventListener("beforeunload",()=>{
util.local.get(Setting.tokenKey) && util.local.set(Setting.storeKey,this.$store.state)
})
}
}
</script>

@ -0,0 +1,158 @@
import Setting from '@/setting'
let host = `${Setting.apiBaseURL}evaluation/`
let loginhost = `${Setting.apiBaseURL}liuwanr/`
export default {
host,
logins: `${loginhost}userInfo/logins`, //登录 
updateLogInNumber: `${loginhost}userInfo/updateLogInNumber`, //用户登录修改登录次数和登陆时间
uploadUserAvatars: `${loginhost}userInfo/uploadUserAvatars`, //上传头像
loginSchool: `${loginhost}userInfo/loginSchoolClient`, //登陆查询学校
loginRole: `${loginhost}userInfo/loginRole`, //登陆查询角色
save: `${host}tms/userInfo/add`, //注册
queryToken: `${loginhost}userInfo/queryToken`,
queryWorkNumberIsExist:`${loginhost}userInfo/queryWorkNumberIsExist`,//查询学号、工号是否存在
queryAccountIsExist:`${loginhost}userInfo/queryAccountIsExist`,//查询员工,学生账号是否存在接口
addStuPro: `${host}stuProfessionalArchitecture/addStuProfessionalArchitecture`, //添加学生专业
queryStuPro: `${host}stuProfessionalArchitecture/queryStuProfessionalArchitecture`, //查询学生专业
queryStuGrade: `${host}stuProfessionalArchitecture/queryStuGrade`, //查询学生年级
queryStuClass: `${host}stuProfessionalArchitecture/queryStuClass`, //查询学生班级
deleteStuPro: `${host}stuProfessionalArchitecture/deleteStuProfessionalArchitecture`, //删除学生专业
updateStuPro: `${host}stuProfessionalArchitecture/updateStuProfessionalArchitecture`, //编辑学生专业
findPasswordByEmail: `${host}tms/userInfo/findPasswordByEmail`,
findPasswordByPhone: `${host}tms/userInfo/findPasswordByPhone`,
resetPassword: `${host}tms/userInfo/resetPassword`,
checkCode: `${host}tms/userInfo/checkCode`,
queryStudentData: `${host}student/queryStudent`, //查询学生
queryStudentDetails: `${host}student/queryStudentDetails`, //查询学生详情
addStudent: `${host}student/addStudent`, //添加学生
deleteStudent: `${host}student/deleteStudent`, //删除学生
updateStudent: `${host}student/updateStudent`, //编辑学生
updateStuGrade: `${host}stuProfessionalArchitecture/updateStuGrade`, //编辑学生年级
addStuGrade: `${host}stuProfessionalArchitecture/addStuGrade`, //添加学生年级
deleteStuGrade: `${host}stuProfessionalArchitecture/deleteStuGrade`, //删除学生年级
updateStuClass: `${host}stuProfessionalArchitecture/updateStuClass`, //编辑学生班级
addStuClass: `${host}stuProfessionalArchitecture/addStuClass`, //添加学生班级
deleteStuClass: `${host}stuProfessionalArchitecture/deleteStuClass`, //删除学生班级
queryPersonalCenter:`${host}personalCenter/queryPersonalCenter`,
addStaffPro: `${host}staffProfessionalArchitecture/addStaffProfessionalArchitecture`, //添加员工专业
queryStaffPro: `${host}staffProfessionalArchitecture/queryAllStaffProfessionalArchitecture`, //查询员工专业
deleteStaffPro: `${host}staffProfessionalArchitecture/deleteStaffProfessionalArchitecture`, //删除员工专业
deleteStaffGrade: `${host}staffGrade/deleteStaffGrade`, //删除员工部门
updateStaffPro: `${host}staffProfessionalArchitecture/updateStaffProfessionalArchitecture`, //编辑员工专业
queryStaffGrade: `${host}staffGrade/queryStaffGrade`, //查询员工部门
queryStaffGradeDetails: `${host}staffGrade/queryStaffGradeDetails`, //查询员工部门详情
addStaffGrade: `${host}staffGrade/addStaffGrade`, //新增员工部门
updateStaffGrade: `${host}staffGrade/updateStaffGrade`, //编辑员工部门
queryCourseDiscipline: `${loginhost}course/queryCourseDiscipline`, //查询课程学科
queryCourseProfessionalClass: `${loginhost}course/queryCourseProfessionalClass`, //查询专业类
queryCourseProfessional: `${loginhost}course/queryCourseProfessional`, //查询专业
queryPhone: `${loginhost}userInfo/queryPhone`, //查询电话是否存在
queryStaff: `${host}staff/queryStaff`, //查询员工
addStaff: `${host}staff/addStaff`, //添加员工
queryStaffDetails: `${host}staff/queryStaffDetails`, //员工详情
deleteStaff: `${host}staff/deleteStaff`, //删除员工
updateStaff: `${host}staff/updateStaff`, //更新员工
readStaff: `${host}staff/readStaff`, //上传员工模板
queryGetByClassName:`${host}makeuplist/queryGetByClassName`,
deleteExperimentalClass:`${host}experimentalClass/deleteExperimentalClass`,//删除实验班级
queryAssesmentcondition:`${host}assesment/queryAssesmentcondition`,//考核成绩表格
queryGetById:`${host}assesment/queryGetById`,//查询考核信息
updateAssesment:`${host}assesment/updateAssesment`,//修改考核
updateState:`${host}assesment/updateState`,//点击启动修改考核时间
updateAssesmentTime:`${host}assesment/updateAssesmentTime`,//点击提前结束获取当前时间
queryAssesmentScore:`${host}assesment/queryAssesmentScore`,//获取查询成绩页面
queryAssesmentAchievement:`${host}assesment/queryAssesmentAchievement`,//查询成绩明细板块
excelExport:`${host}makeuplist/excelExport`,//模板下载
importMakeuplist:`${host}makeuplist/importMakeuplist`, //模板上传
queryAllExperiment:`${host}experiment/queryAllExperiment`,//实验项目渲染,
queryAttendanceSignIn:`${host}attendance/queryAttendanceSignIn`,//获得用户ID 及考勤总数
insertAttendance:`${host}Experimentallearning/insertAttendance`,//改变签到状态
queryExperimentallearning:`${host}Experimentallearning/queryExperimentallearning`,//获取项目名和签到状态
queryCourseDetails:`${host}course/queryCourseDetails`,//获取课程简介和课程目标
queryTeacherName:`${host}Experimentallearning/queryTeacherName`,//获取教师信息
queryStudentName:`${host}Experimentallearning/queryStudentName`,//获取学生信息
queryPracticeVo:`${host}experiment/queryPracticeVo`,//获取表格数据
queryStudentAssessment:`${host}assesmentRecord/queryStudentAssessment`, //查询姓名和个人平均分和最高分
queryAssesmentRecordMaxScore:`${host}assesmentRecord/queryAssesmentRecordMaxScore`, //查询学校平均分最高分
queryAssesmentRecordWhole:`${host}assesmentRecord/queryAssesmentRecordWhole`,//查询全国平均考核得分
queryAssesmentRecordMaxWhole:`${host}assesmentRecord/queryAssesmentRecordMaxWhole`, //查询全国平均分最高分
queryStudentByPage:`${host}experiment/queryStudentByPage`, //查询练习记录表格数据
queryProject:`${host}ProjectAndCourse/queryProject`,//实验项目信息展示
updateIsExperiment:`${host}ProjectAndCourse/updateIsExperiment`,//修改是否开启项目
updateIsAttendance:`${host}ProjectAndCourse/updateIsAttendance`,//修改是否考勤
addAssesment:`${host}assesment/addAssesment`,//添加考核
queryStuProfessionalArchitecture:`${host}stuProfessionalArchitecture/queryStuProfessionalArchitecture`,//修改是否考勤
queryStuGrade:`${host}stuProfessionalArchitecture/queryStuGrade`,//修改是否考勤
queryStuClass:`${host}stuProfessionalArchitecture/queryStuClass`,//修改是否考勤
queryStudent:`${host}stuProfessionalArchitecture/queryStudent`,//修改是否考勤
queryAttendanceDetailed:`${host}attendance/queryAttendanceDetailed`,//获取考勤列表数据
queryExperimentClass:`${host}experimentalClass/queryExperimentalClass`,//查询实验班级
queryExperimentalClassSP:`${host}experimentalClass/queryExperimentalClassSP`,//查询实验班级学生专业
queryStudentClass:`${host}experimentalClass/queryStudentClass`,//查询学生行政班级
queryClassDetails:`${host}experimentalClass/queryExperimentClassDetails`,//查询实验班级详情
updateClassName:`${host}experimentalClass/updateExperimentClassName`,//修改实验班级名称
updateState:`${host}assesment/updateState`,//修改考核状态
experimentClassDeleteStudent:`${host}experimentalClass/experimentClassDeleteStudent`, //移除实验班学生
addExperimentalClass:`${host}experimentalClass/addExperimentalClass`,//添加实验班级
platformQueryCourse:`${host}course/platformQueryCourse`,
queryAssesment:`${host}Experimentallearning/queryAssesment`,
getCourse:`${host}course/getCourse`,//获取课程简介,教学目标,课程名称
getProfessionals:`${host}experimentalClass/getProfessionals`,// 请求专业下拉框数据
getStudentClass:`${host}experimentalClass/getStudentClass`,//请求行政班级下拉框数据
getCourseSchedule:`${host}ProjectAndCourse/getCourseSchedule`,//课程进度
releaseAssesment:`${host}assesment/releaseAssesment`,//发布考核
experimentClassAddStudent:`${host}experimentalClass/experimentClassAddStudent`,//发布考核
getExperimentalClass:`${host}assesment/getExperimentalClass`,//实验班级一级标题
getCreationTime:`${host}assesment/getCreationTime`,//实验班级二级标题
deleteAssesment:`${host}assesment/deleteAssesment`,//删除考核
queryStudentCourse:`${host}Experimentallearning/queryStudentCourse`,//学生查询课程
getByCourseId:`${host}assesment/getByCourseId`,//查询系统列表
getCoursevideo:`${host}tms/classTech/simulationPlayList`,//开始课程-课程视频
queryStaffPAN:`${host}staffProfessionalArchitecture/queryStaffPAN`,//查询员工专业是否存在
queryStudentisAssess:`${host}assesment/queryStudentisAssess`,//查看正在参与考核的学生
queryProvince: `${loginhost}province/queryProvince`, //查询省份
queryCity: `${loginhost}city/queryCity`, //查询城市
querySchoolData: `${loginhost}customer/querySchool`, //根据学校名称查询学校信息
examinePassword:`${host}tms/user/examinePassword`,//更换密码
userinfoUpdate:`${host}tms/user/update`,//个人中心信息修改
userinfo:`${host}tms/user/userinfo`,//个人中心信息展示
sendEmailCode:`${host}tms/user/sendEmailCode`,//发送邮箱验证码
bingEmail:`${host}tms/user/bingEmail`,//邮箱验证并更新
sendPhoneCode:`${host}tms/user/sendPhoneCode`,//发送手机验证码
bindPhone:`${host}tms/user/bindPhone`,//校验手机验证码
canExperiment: `${host}tms/evaluationrecord/can_experiment`, //查询是否能够开启实验
openExercise: `${host}tms/evaluationrecord/openExercise`, //查询是否能够开启虚拟仿真实验
openTeaching: `${host}tms/evaluationrecord/openTeaching`, //查询是否能够开启教学实验
experimentDetail: `${host}tms/evaluationrecord/detail`, //成绩详情
experimentNext: `${host}tms/evaluationrecord/next`, //下一题
experimentNotmade: `${host}tms/evaluationrecord/not_made`, //提交之前查询是否还有未做完的试题
experimentPrevious: `${host}tms/evaluationrecord/previous`, //上一题
experimentRemaining: `${host}tms/evaluationrecord/remaining`, //获取测评剩余时间
experimentStart: `${host}tms/evaluationrecord/start`, //开始测评
experimentSubmit: `${host}tms/evaluationrecord/submit`, //提交测评
fictitiousRecord: `${host}fictitious/projectrecord/user/record`, //用户端实验记录
exportProjectRecord: `${host}fictitious/projectrecord/user/exportProjectRecord`, //虚拟实验记录导出
exportExperimentProjectRecord: `${host}fictitious/projectrecord/user/exportExperimentProjectRecord`, //个人实验记录导出
fictitiousScore: `${host}fictitious/projectrecord/user/score`, //个人实验概览
experimentRecord: `${host}fictitious/projectrecord/user/experimentRecord`, //用户端教学实验记录
joinPractice: `${host}tms/classTech/joinPractice`, //通过邀请码进入实验
queryArchievement: `${host}tms/classTech/queryExperimentalReport`, //查看教学实验报告
queryVirtualReport: `${host}tms/classTech/queryVirtualReport`, //查看虚仿实验报告
checkInvitationCode: `${host}tms/classTech/checkInvitationCode`, //校验是否需要邀请码
userRecord: `${host}tms/classTech/userRecord`, //查询班级实验列表信息
modifyReport: `${host}Achievement/modify`,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

@ -0,0 +1,124 @@
<template>
<div>
<el-dialog
custom-class="pdf-dia"
:close-on-click-modal="false"
:visible.sync="visible"
@close="closePdf"
:fullscreen="true"
:modal="false"
:append-to-body="true">
<div>
<button type="button" aria-label="Close" class="el-dialog__headerbtn" @click="closePdf"><i class="el-dialog__close el-icon el-icon-close"></i></button>
<div class="pdf">
<p class="arrow">
<span @click="changePdfPage(0)" class="turn el-icon-arrow-left" :class="{grey: currentPage==1}"></span>
{{currentPage}} / {{pageCount}}
<span @click="changePdfPage(1)" class="turn el-icon-arrow-right" :class="{grey: currentPage==pageCount}"></span>
</p>
<pdf
class="pdf-wrap"
:src="src"
:page="currentPage"
@num-pages="pageCount=$event"
@page-loaded="currentPage=$event"
@loaded="loadPdfHandler"
>
</pdf>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import pdf from "vue-pdf";
export default {
props: ['visible','src'],
data() {
return {
pdfVisible: false,
pdfSrc: '',
currentPage: 0,
pageCount: 0,
fileType: 'pdf',
};
},
components: { pdf },
mounted(){
this.addEvent()
},
methods: {
closePdf(){
this.$emit('update:visible',false)
this.$emit('update:src','')
this.currentPage = 1
},
changePdfPage (val) {
if (val === 0 && this.currentPage > 1) {
this.currentPage--
}
if (val === 1 && this.currentPage < this.pageCount) {
this.currentPage++
}
},
loadPdfHandler (e) {
this.currentPage = 1
},
addEvent(){
document.onkeydown = e => {
let key = window.event.keyCode
if(key == 37){
this.changePdfPage(0)
}else if(key == 39){
this.changePdfPage(1)
}
}
this.$once('hook:beforeDestroy',() => {
document.onkeydown = null
})
}
}
};
</script>
<style lang="scss" scoped>
/deep/.pdf-dia{
border-radius: 0 !important;
.el-dialog__header{
display: none;
}
.el-dialog__body{
padding: 0;
}
.el-dialog__headerbtn{
top: 10px;
.el-dialog__close{
color: #fff;
font-size: 16px;
}
}
.pdf{
.arrow{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 10px 0;
font-size: 16px;
color: #fff;
background-color: #333;
.turn{
margin: 0 10px;
font-size: 18px;
cursor: pointer;
}
}
.pdf-wrap{
height: calc(100vh - 45px);
margin: 0 auto;
overflow: auto;
}
}
}
</style>

@ -0,0 +1,179 @@
<template>
<div class="quill" :class="classes">
<div ref="editor" :style="styles" v-loading="loading"></div>
<el-upload :action="this.api.fileupload" :before-upload="beforeUpload" :on-success="editorUploadSuccess" style="display: none">
<el-button class="editorUpload" size="small" type="primary">点击上传</el-button>
</el-upload>
</div>
</template>
<script>
import Quill from 'quill';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import toolbarOptions from './options'
export default {
name: 'quill',
props: {
value: {
type: String,
default: ''
},
readonly: {
type: Boolean,
default: false
},
toTop: {
type: Boolean,
default: true
},
border: {
type: Boolean,
default: false
},
height: {
type: Number
},
minHeight: {
type: Number
}
},
data () {
return {
Quill: null,
currentValue: '',
options: {
theme: 'snow',
bounds: document.body,
debug: 'warn',
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
'image': function (value) {
if (value) {
// iview
document.querySelector('.editorUpload').click()
} else {
this.Quill.format('image', false);
}
}
}
}
},
placeholder: '',
readOnly: this.readonly
},
loading: false
}
},
computed: {
classes () {
return [
{
'quill-no-border': !this.border
}
];
},
styles () {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
}
},
watch: {
value: {
handler (val) {
if (val !== this.currentValue) {
this.currentValue = val;
if (this.Quill) {
this.Quill.pasteHTML(this.value);
}
}
},
immediate: true
}
},
mounted () {
this.init();
},
beforeDestroy () {
//
this.Quill = null;
},
methods: {
init () {
const editor = this.$refs.editor;
//
this.Quill = new Quill(editor, this.options);
//
this.Quill.pasteHTML(this.currentValue);
if(this.toTop){
this.$nextTick(() => {
window.scrollTo(0,0)
})
}
//
this.Quill.on('text-change', (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText();
const quill = this.Quill;
//
this.currentValue = html;
// v-model
this.$emit('input', html);
//
this.$emit('on-change', { html, text, quill });
});
// quill
this.Quill.on('text-change', (delta, oldDelta, source) => {
this.$emit('on-text-change', delta, oldDelta, source);
});
this.Quill.on('selection-change', (range, oldRange, source) => {
this.$emit('on-selection-change', range, oldRange, source);
});
this.Quill.on('editor-change', (eventName, ...args) => {
this.$emit('on-editor-change', eventName, ...args);
});
},
beforeUpload(file){
this.loading = true
},
editorUploadSuccess (res) {
//
let quill = this.Quill
//
if (res.data.filesResult.fileUrl) {
//
let length = quill.getSelection().index;
// res
quill.insertEmbed(length, 'image', res.data.filesResult.fileUrl)
//
quill.setSelection(length + 1)
} else {
this.$message.success('图片插入失败')
}
this.loading = false
},
}
}
</script>
<style lang="scss" scoped>
.quill-no-border{
.ql-toolbar.ql-snow{
border: none;
border-bottom: 1px solid #e8eaec;
}
.ql-container.ql-snow{
border: none;
}
}
</style>

@ -0,0 +1,16 @@
export default [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'script': 'sub' }, { 'script': 'super' }],
[{ 'indent': '-1' }, { 'indent': '+1' }],
[{ 'direction': 'rtl' }],
[{ 'size': ['small', false, 'large', 'huge'] }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }],
[{ 'font': [] }],
[{ 'align': [] }],
['clean'],
['link', 'image', 'video']
]

@ -0,0 +1,30 @@
export const messages = {
'zh': {
i18n: {
breadcrumb: '国际化产品',
tips: '通过切换语言按钮,来改变当前内容的语言。',
btn: '切换英文',
title1: '常用用法',
p1: '要是你把你的秘密告诉了风,那就别怪风把它带给树。',
p2: '没有什么比信念更能支撑我们度过艰难的时光了。',
p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。',
title2: '组件插值',
info: 'Element组件需要国际化,请参考 {action}。',
value: '文档'
}
},
'en': {
i18n: {
breadcrumb: 'International Products',
tips: 'Click on the button to change the current language. ',
btn: 'Switch Chinese',
title1: 'Common usage',
p1: "If you reveal your secrets to the wind you should not blame the wind for revealing them to the trees.",
p2: "Nothing can help us endure dark times better than our faith. ",
p3: "If you can do what you do best and be happy, you're further along in life than most people.",
title2: 'Component interpolation',
info: 'The default language of Element is Chinese. If you wish to use another language, please refer to the {action}.',
value: 'documentation'
}
}
}

@ -0,0 +1,43 @@
<template>
<div>
<div class="copyright">
<a href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">粤ICP备20072679号</a>
</div>
</div>
</template>
<script>
export default {
data() {
return {
};
},
mounted(){
},
methods: {
},
};
</script>
<style lang="scss" scoped>
.copyright{
padding: 20px 0;
color: rgba(0, 0, 0, 0.45);
font-size: 12px;
text-align: center;
background-color: #333;
p{
margin-bottom: 10px;
color: #fff;
font-size: 12px;
}
a{
color:#fff;
font-size: 12px;
&:hover{
opacity: .8;
}
}
}
</style>

@ -0,0 +1,121 @@
<template>
<div class="header">
<div v-if="this.$route.path=='/setting/person'" class="goBack" @click="back"><i class="el-icon-arrow-left"></i>返回</div>
<template v-else>
<img class="logo hh" v-if="isHh" src="@/assets/img/logo-hh.png" />
<img class="logo" v-else src="@/assets/img/logo.png">
</template>
<div class="header-right">
<div class="header-user-con">
<div class="user" @click="toPersonal">
<el-avatar :size="40" :src="avatar"></el-avatar>
<span class="user-avator">{{userName}}</span>
</div>
<el-divider class="ml20" direction="vertical"></el-divider>
<el-button type="text" class="ml20" @click="logout">退出</el-button>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import util from '@/libs/util'
import Setting from '@/setting'
export default {
data() {
return {
isHh: Setting.isHh,
};
},
computed: {
...mapState('user', [
'avatar','userName'
]),
},
mounted(){
},
methods: {
...mapActions('user', [
'logout'
]),
toPersonal(){
this.$router.push('/setting/person')
},
back(){
if(this.$route.path == '/addassessment'){
this.$router.push({ path: '/teacherhome', query: { active: true }})
}else{
this.$router.go(-1)
}
}
},
};
</script>
<style scoped lang="scss">
.goBack{
cursor: pointer;
line-height: 60px;
height: 60px;
font-size: 16px;
font-weight: bold;
margin-left: 20px;
}
.goBack i{
color: #9278ff;
font-size: 20px;
}
.header {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
width: 100%;
height: 60px;
font-size: 16px;
color: #333;
}
.header .logo {
width: 150px;
margin-left: 20px;
&.hh{
width: 500px;
}
}
.header-right {
padding-right: 50px;
}
.header-user-con {
display: flex;
align-items: center;
.user{
display: inline-flex;
align-items: center;
cursor: pointer;
}
}
.user-avator {
margin-left: 10px;
}
.ml20{
margin-left: 20px;
}
.user-avator img {
display: block;
width: 40px;
height: 40px;
border-radius: 50%;
}
.header-right .el-button--text{
color: #333;
}
.header-right .el-divider--vertical{
width: 2px;
height: 15px;
}
.header-right .el-divider{
background-color: #333;
}
</style>

@ -0,0 +1,69 @@
<template>
<div class="main">
<v-head></v-head>
<div class="layout">
<navbar v-if="!hideNavList.includes($route.path)"></navbar>
<div class="content">
<transition name="move" mode="out-in">
<router-view class="view"></router-view>
</transition>
<el-backtop target=".content"></el-backtop>
<v-footer ref="footer"></v-footer>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import util from '@/libs/util'
import Setting from '@/setting'
import vHead from '../header'
import navbar from '../navbar'
import vFooter from '../footer'
export default {
data() {
return {
hideNavList: ['/record/show','/setting/person']
};
},
components: {
vHead,
navbar,
vFooter
},
computed: {
},
mounted() {
this.autoLogout()
},
methods: {
...mapActions('user', [
'logout'
]),
autoLogout(){
let lastTime = new Date().getTime()
document.onmousedown = () => {
lastTime = new Date().getTime()
}
setInterval(() => {
if(util.local.get(Setting.tokenKey) && (new Date().getTime() - lastTime) > Setting.autoLogoutTime){
util.errorMsg('用户登录过期,请重新登录')
setTimeout(this.logout,1500)
}
},1000)
}
}
};
</script>
<style lang="scss" scoped>
.main{
min-height: 100%;
.view{
min-height: calc(100vh - 175px);
padding: 24px;
}
}
</style>

@ -0,0 +1,69 @@
<template>
<div>
<el-tabs v-model="active" @tab-click="jump">
<el-tab-pane v-for="(item,index) in menus" :key="index" :label="item.label" :name="item.index"></el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import { mapState,mapActions } from 'vuex'
import Setting from '@/setting'
import util from '@/libs/util'
export default {
data() {
return {
active: this.$route.path,
menus: [
{
index: '/preview/list',
label: '课前预习'
},
{
index: '/station/list',
label: '实验台'
},
{
index: '/ass/list',
label: '考核列表'
},
{
index: '/record/list',
label: '实验记录'
},
],
};
},
watch: {
'$route'(to,from) {
this.active = this.$route.path
}
},
mounted() {
},
methods: {
jump(tab){
this.active = tab.name
this.$router.push(tab.name).catch(err => {})
},
}
};
</script>
<style lang="scss" scoped>
/deep/.el-tabs__header{
z-index: 2;
padding: 20px 60px 0;
margin: 0;
box-shadow:0px 0px 25px 2px rgba(48,115,248,0.14);
background-color: #fff;
.el-tabs__nav-wrap::after{
background-color: #fff;
.el-tabs__item{
padding: 0 30px;
outline: none;
}
}
}
</style>

@ -0,0 +1,25 @@
/**
* @description 生成按钮级别权限组
* */
import store from '@/store';
export default function(data){
let result = []
data.map(e => {
if(e.select){
e.children.map(n => {
if(n.select){
if(n.children.length){
result.push(`${e.name}:${n.name}`)
n.children.map(j => {
j.select && (e.path ? result.push(`${e.path}:${n.name}:${j.name}`) : result.push(`${n.path}:${j.name}`))
})
}else{
result.push(`${e.path}:${n.name}`)
}
}
})
}
})
store.dispatch('auth/addBtnAuth',result)
}

@ -0,0 +1,6 @@
import Vue from 'vue';
// 使用 Event Bus
const bus = new Vue();
export default bus;

@ -0,0 +1,10 @@
// 生成随机字符串
export default function (len = 32) {
const $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
const maxPos = $chars.length;
let str = '';
for (let i = 0; i < len; i++) {
str += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return str;
}

@ -0,0 +1,16 @@
// rem等比适配配置文件
// 基准大小
const baseSize = 16
// 设置 rem 函数
function setRem () {
// 当前页面宽度相对于 1920宽的缩放比例,可根据自己需要修改。
const scale = document.documentElement.clientWidth / 1920
// 设置页面根节点字体大小(“Math.min(scale, 2)” 指最高放大比例为2,可根据实际业务需求调整)
document.documentElement.style.fontSize = baseSize * Math.min(scale, 2) + 'px'
}
// 初始化
setRem()
// 改变窗口大小时重新设置 rem
window.onresize = function () {
setRem()
}

@ -0,0 +1,32 @@
import store from '@/store';
import router from '@/router';
import generateBtnPermission from '../auth/generateBtnPermission';
const newRoutes = []
function createMeta(item){
let meta = { title: item.name }
return meta
}
function createRoute(data){
data.map(e => {
if(e.select && e.path){
let meta = createMeta(e)
newRoutes.push({
name: e.path,
path: e.path,
path: () => import(`@/pages/${e.path}.vue`),
meta
})
}
e.children && e.children.length && createRoute(e.children)
})
}
export default function(data,path){
generateBtnPermission(data)
createRoute(data)
store.dispatch('auth/addRoutes',newRoutes)
// router.addRoutes(routes)
}

@ -0,0 +1,26 @@
import store from '@/store';
import router from '@/router';
export default function(){
setTimeout(() => {
let routes = store.state.auth.routes
routes.forEach(e => {
if(e.path == '/'){
e.component = () => import('@/layouts/home/index.vue')
}else{
e.component = () => import(`@/pages/${e.path}.vue`)
}
e.children && e.children.forEach(n => {
n.path && (n.component = () => import(`@/pages/${n.path}.vue`))
})
})
routes.push({
path: '*',
redirect: '404'
})
router.addRoutes(routes)
},500)
}

@ -0,0 +1,6 @@
import router from '@/router';
export default function(){
const newRouter = createRouter()
router.matcher = newRouter.matcher
}

@ -0,0 +1,43 @@
import Cookies from 'js-cookie';
import Setting from '@/setting';
const cookies = {};
/**
* @description 存储 cookie
* @param {String} name cookie name
* @param {String} value cookie value
* @param {Object} cookieSetting cookie setting
*/
cookies.set = function (name = 'default', value = '', cookieSetting = {}) {
let currentCookieSetting = {
expires: Setting.cookiesExpires
};
Object.assign(currentCookieSetting, cookieSetting);
Cookies.set(`admin-${name}`, value, currentCookieSetting);
};
/**
* @description 拿到 cookie
* @param {String} name cookie name
*/
cookies.get = function (name = 'default') {
return Cookies.get(`admin-${name}`);
};
/**
* @description 拿到 cookie 全部的值
*/
cookies.getAll = function () {
return Cookies.get();
};
/**
* @description 删除 cookie
* @param {String} name cookie name
*/
cookies.remove = function (name = 'default') {
return Cookies.remove(`admin-${name}`);
};
export default cookies;

@ -0,0 +1,83 @@
/**
* localStorage
* @调用_local.set('access_token', '123456', 5000);
* @调用_local.get('access_token');
*/
var _local = {
//存储,可设置过期时间
set(key, value, expires) {
let params = { key, value, expires };
if (expires) {
// 记录何时将值存入缓存,毫秒级
var data = Object.assign(params, { startTime: new Date().getTime() });
localStorage.setItem(key, JSON.stringify(data));
} else {
if (Object.prototype.toString.call(value) == '[object Object]') {
value = JSON.stringify(value);
}
if (Object.prototype.toString.call(value) == '[object Array]') {
value = JSON.stringify(value);
}
localStorage.setItem(key, value);
}
},
//取出
get(key) {
let item = localStorage.getItem(key);
// 先将拿到的试着进行json转为对象的形式
try {
item = JSON.parse(item);
} catch (error) {
// eslint-disable-next-line no-self-assign
item = item;
}
// 如果有startTime的值,说明设置了失效时间
if (item && item.startTime) {
let date = new Date().getTime();
// 如果大于就是过期了,如果小于或等于就还没过期
if (date - item.startTime > item.expires) {
localStorage.removeItem(key);
return false;
} else {
return item.value;
}
} else {
return item;
}
},
// 删除
remove(key) {
localStorage.removeItem(key);
},
// 清除全部
clear() {
localStorage.clear();
}
}
/**
* sessionStorage
*/
var _session = {
get: function (key) {
var data = sessionStorage[key];
if (!data || data === "null") {
return null;
}
return data;
},
set: function (key, value) {
sessionStorage[key] = value;
},
// 删除
remove(key) {
sessionStorage.removeItem(key);
},
// 清除全部
clear() {
sessionStorage.clear();
}
}
export { _local, _session }

@ -0,0 +1,159 @@
import cookies from './util.cookies'
import {_local,_session} from './util.db'
import { Message } from 'element-ui'
import store from '@/store'
import axios from 'axios'
import api from '@/api'
import Setting from '@/setting'
let logout = false
const util = {
cookies,
local: _local,
session: _session,
// 传入身份证获取生日
getBirth(idCard) {
var birthday = "";
if(idCard != null && idCard != ""){
if(idCard.length == 15){
birthday = "19"+idCard.slice(6,12);
} else if(idCard.length == 18){
birthday = idCard.slice(6,14);
}
birthday = birthday.replace(/(.{4})(.{2})/,"$1-$2-");
//通过正则表达式来指定输出格式为:1990-01-01
}
return birthday;
},
// new Date('2020-11-12 00:00:00') 在IE下失效,因此把-替换成/
dateCompatible(date) {
return date.replace(/\-/g, '/')
},
// 日期时间前面补零
formateTime(num) {
return num < 10 ? `0${num}` : num
},
//返回格式化时间,传参例如:"yyyy-MM-dd hh:mm:ss"
formatDate(fmt,date) {
var date = date ? date : new Date()
var o = {
"M+" : date.getMonth()+1, //月份
"d+" : date.getDate(), //日
"h+" : date.getHours(), //小时
"m+" : date.getMinutes(), //分
"s+" : date.getSeconds(), //秒
"q+" : Math.floor((date.getMonth()+3)/3), //季度
"S" : date.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt)) {
fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
}
for(var k in o) {
if(new RegExp("("+ k +")").test(fmt)){
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
}
}
return fmt;
},
// 移除数组中指定值
removeByValue(arr, val) {
for(var i=0; i<arr.length; i++) {
if(arr[i] == val) {
arr.splice(i, 1);
break;
}
}
},
// 传入文件后缀判断是否是视频
isVideo(ext) {
if('mp4,3gp,mov,m4v,avi,dat,mkv,flv,vob,rmvb,rm,qlv'.includes(ext)) return true
return false
},
// 传入文件后缀判断是否是音频
isAudio(ext) {
if('mp3,aac,ape,flac,wav,wma,amr,mid'.includes(ext)) return true
return false
},
// 传入文件后缀判断是否是图片
isImg(ext) {
if('jpg,jpeg,png,gif,svg,psd'.includes(ext)) return true
return false
},
// 传入文件后缀判断是否是pdf以外的文档
isDoc(ext) {
if(!util.isVideo(ext) && !util.isAudio(ext) && !util.isImg(ext) && ext != 'pdf') return true
return false
},
// 循环去除html标签
removeHtmlTag(list,attr) {
list.map(n => {
n[attr] = n[attr].replace(/<\/?.+?>/gi,'')
})
return list
},
// 传入文件名获取文件后缀
getFileExt(fileName) {
return fileName.substring(fileName.lastIndexOf('.') + 1)
},
// 传入文件名和路径,下载图片视频,支持跨域,a标签加download不支持跨域
downloadFile(fileName,url) {
var x = new XMLHttpRequest()
x.open("GET", url, true)
x.responseType = 'blob'
x.onload=function(e) {
var url = window.URL.createObjectURL(x.response)
var a = document.createElement('a')
a.href = url
a.download = fileName
a.click()
}
x.send()
},
// 传入文件名和数据,下载文件
downloadFileDirect(fileName,data) {
if ('download' in document.createElement('a')) { // 非IE下载
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(data)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href) // 释放URL 对象
document.body.removeChild(elink)
} else { // IE10+下载
navigator.msSaveBlob(data, fileName)
}
},
// 成功提示
successMsg(message,duration = 3000) {
return Message.success({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration})
},
// 警告提示
warningMsg(message,duration = 3000) {
return Message.warning({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration})
},
// 错误提示
errorMsg(message,duration = 3000) {
return Message.error({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration})
},
// 登录互踢
getToken(){
if(process.env.NODE_ENV == 'production'){
if(store.state.user.dataTime && !logout){
axios.get(`${api.queryToken}?token=${_local.get(Setting.tokenKey)}`).then(res => {
if(store.state.user.dataTime && (res.data.message != store.state.user.dataTime)){
logout || Message.error('您已在另一台设备登录,本次登录已下线!')
logout = true
setTimeout(() => {
_local.remove(Setting.storeKey)
_local.remove(Setting.tokenKey)
location.reload()
},1500)
}
}).catch(err => {})
}
}
}
}
export default util

@ -0,0 +1,45 @@
import Vue from 'vue';
import App from '@/App.vue';
import router from '@/router';
import ElementUI from 'element-ui';
import '@/styles/index.scss'
import VueI18n from 'vue-i18n';
import mixinApp from '@/mixins/app';
import { messages } from '@/i18n';
import 'babel-polyfill';
import '@/libs/resize';
import {post,get,del,put} from '@/plugins/requests/index.js';
import api from '@/api';
import store from '@/store'
import Setting from '@/setting';
import permission from '@/router/permission';
// 插件
import plugins from '@/plugins';
import filters from '@/plugins/filters'
Vue.use(plugins);
Object.keys(filters).forEach(item => Vue.filter(item,filters[item]))
Vue.prototype.api = api;
Vue.prototype.$get = get;
Vue.prototype.$post = post;
Vue.prototype.$del = del;
Vue.prototype.$put = put;
Vue.config.productionTip = false;
Vue.use(VueI18n);
Vue.use(ElementUI);
const i18n = new VueI18n({
locale: Setting.i18n.default,
messages
});
new Vue({
mixins: [mixinApp],
router,
i18n,
store,
render: h => h(App)
}).$mount('#app');

@ -0,0 +1,11 @@
/**
* 通用混合
* */
export default {
methods: {
// 当 $route 更新时触发
appRouteChange (to, from) {
}
}
}

@ -0,0 +1,8 @@
export default {
beforeCreate() {
document.querySelector('body').setAttribute('style', 'background-color:#fff')
},
beforeDestroy() {
document.body.removeAttribute('style')
}
}

@ -0,0 +1,574 @@
<template>
<div class="wrap">
<div class="header" v-if="!isHh">
<img class="logo" src="@/assets/img/logo.png" />
</div>
<div class="bg">
<div class="left">
<div class="text" v-if="isHh">
<p>欢迎使用</p>
<p style="margin-bottom: 15px">商学院金融工程</p>
<p>与大数据实验平台</p>
</div>
<div class="text" v-else>
<p>欢迎使用</p>
<p>Occupation Lab</p>
</div>
</div>
<div class="right"></div>
</div>
<div class="right-form">
<img v-if="isHh" class="logo" src="@/assets/img/logo-hh1.png" />
<div class="form">
<div class="back" v-show="isReg" @click="toReg(false)">
<i class="el-icon-back"></i>
</div>
<div v-if="!isReg">
<el-tabs v-model="activeName">
<el-tab-pane label="账号登录" name="0">
<el-form :model="loginForm" :rules="loginRules" ref="loginForm" style="margin-top: 20px">
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
placeholder="请输入密码"
v-model="loginForm.password"
@keyup.enter.native="getSchool('loginForm')"
>
</el-input>
</el-form-item>
<el-button class="submit" type="primary" @click="getSchool('loginForm')">登录</el-button>
</el-form>
</el-tab-pane>
<el-tab-pane label="手机号/邮箱登录" name="1">
<el-form :model="phoneParam" :rules="phoneRules" ref="phoneParam" style="margin-top: 20px">
<el-form-item label="手机号/邮箱" prop="userphone">
<el-input v-model="phoneParam.userphone" placeholder="请输入手机号/邮箱"></el-input>
</el-form-item>
<el-form-item label="密码" prop="phonePassword">
<el-input
type="password"
placeholder="请输入密码"
v-model="phoneParam.phonePassword"
@keyup.enter.native="getSchool('phoneParam')"
>
</el-input>
</el-form-item>
<el-button class="submit" type="primary" @click="getSchool('phoneParam')">登录</el-button>
</el-form>
</el-tab-pane>
</el-tabs>
<div class="links">
<!-- <el-button type="text" class="ques" @click="toReg(true)">前往注册</el-button> -->
<el-button type="text" class="forget" @click="forget">忘记密码</el-button>
</div>
</div>
<register v-else :isReg.sync="isReg" @updateInfo="updateInfo"></register>
</div>
</div>
<v-footer ref="footer"></v-footer>
<el-dialog title="选择角色" :visible.sync="roleDialog" width="24%" center :close-on-click-modal="false">
<div>
<el-select v-model="roleId" placeholder="请选择角色">
<el-option v-for="(item,index) in roleList" :key="index" :label="item.roleName" :value="item.roleId"></el-option>
</el-select>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="cancleRoleDia"> </el-button>
<el-button v-if="activeName == '0'" type="primary" @click="roleSure('loginForm')"> </el-button>
<el-button v-else type="primary" @click="roleSure('phoneParam')"> </el-button>
</span>
</el-dialog>
<el-dialog :title="phoneReset ? '手机重置密码' : '邮箱重置密码'" :visible.sync="forgetVisible" :close-on-click-modal="false" @close="closeForget" width="30%">
<template v-if="phoneReset">
<el-form ref="form" label-width="60px">
<el-form-item label="手机号">
<el-input placeholder="请输入手机号" v-model.number="phone" maxlength="11"></el-input>
</el-form-item>
<el-form-item label="验证码">
<div class="flex-between">
<el-input v-model.number="phoneCode" placeholder="请输入验证码" maxlength="6"></el-input>
<el-button style="margin-left: 10px" type="text" @click="sendPhoneCode" :disabled="phoneDisabled">{{phoneBtnText}}</el-button>
</div>
</el-form-item>
<el-form-item label="新密码">
<el-input type="password" placeholder="请输入新密码" v-model="newPassword"></el-input>
</el-form-item>
</el-form>
<div class="switch" @click="switchType(false)"><span>邮箱重置密码</span></div>
<span slot="footer" class="dialog-footer">
<el-button @click="forgetVisible = false"> </el-button>
<el-button type="primary" @click="updatePassword(1)"> </el-button>
</span>
</template>
<template v-else>
<el-form ref="form" label-width="60px">
<el-form-item label="邮箱">
<el-input placeholder="请输入邮箱" v-model="email"></el-input>
</el-form-item>
<el-form-item label="验证码">
<div class="flex-between">
<el-input v-model.number="emailCode" placeholder="请输入验证码" maxlength="6"></el-input>
<el-button style="margin-left: 10px" type="text" @click="sendEmailCode" :disabled="emailDisabled">{{emailBtnText}}</el-button>
</div>
</el-form-item>
<el-form-item label="新密码">
<el-input type="password" placeholder="请输入新密码" v-model="newPassword"></el-input>
</el-form-item>
</el-form>
<div class="switch" @click="switchType(true)"><span>手机重置密码</span></div>
<span slot="footer" class="dialog-footer">
<el-button @click="forgetVisible = false"> </el-button>
<el-button type="primary" @click="updatePassword"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import register from '../register'
import vFooter from '@/layouts/footer'
import { mapState, mapActions } from 'vuex'
import util from '@/libs/util'
import Setting from '@/setting'
export default {
data: function() {
return {
isHh: Setting.isHh,
schoolId: Setting.schoolId,
activeName: '0',
isReg: false,
loginForm: {
username: '',
password: '',
},
loginRules: {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
},
phoneParam: {
userphone: '',
phonePassword: ''
},
phoneRules: {
userphone: [{ required: true, message: '请输入手机号/邮箱', trigger: 'blur' }],
phonePassword: [{ required: true, message: '请输入密码', trigger: 'blur' }],
},
roleDialog: false,
userId: '',
roleId: '',
roleList: [],
forgetVisible: false,
phoneReset: true,
email: '',
emailBtnText: '发送验证码',
emailCode: '',
emailDisabled: false,
emailTimer: null,
phone: '',
phoneBtnText: '发送验证码',
phoneCode: '',
phoneDisabled: false,
phoneTimer: null,
newPassword: '',
emailOpener: '',
phoneOpener: ''
};
},
components: {
register,
vFooter
},
mounted(){
this.$once('hook:beforeDestroy', function () {
clearInterval(this.phoneTimer)
this.phoneTimer = null
clearInterval(this.emailTimer)
this.emailTimer = null
})
},
methods: {
...mapActions('user', [
'setInfo'
]),
getSchool(form) {
this.$refs[form].validate(valid => {
if (valid) {
let data = {
account: this.activeName == '0' ? this.loginForm.username : this.phoneParam.userphone,
password: this.activeName == '0' ? this.loginForm.password : this.phoneParam.phonePassword,
schoolId: this.schoolId,
source: this.activeName
};
this.$get(this.api.loginSchool, data)
.then(res => {
this.schoolList = [...res.message.staffList,...res.message.studentList]
let indexs = {}
this.schoolList = this.schoolList.reduce((cur,next) => {
indexs[next.schoolId] ? '' : indexs[next.schoolId] = true && cur.push(next)
return cur
},[])
if(this.schoolList.length >= 1) {
this.schoolId = this.schoolList[0].schoolId
this.userId = this.schoolList[0].userId
this.studentId = this.schoolList[0].studentId
this.getRole(form)
}else{
util.errorMsg('账号不存在')
}
})
.catch(res => {})
} else {
util.errorMsg('请输入账号和密码')
return false
}
});
},
getRole(form) {
let data = {
userId: this.userId,
schoolId: this.schoolId
};
this.$get(this.api.loginRole, data)
.then(res => {
this.roleList = [...res.message.staffList,...res.message.studentList]
let indexs = {}
this.roleList = this.roleList.reduce((cur,next) => {
indexs[next.roleId] ? '' : indexs[next.roleId] = true && cur.push(next)
return cur
},[])
this.roleList.forEach((n,k) => {
switch(n.roleId){
case 2:
n.roleName = '管理员'
break
case 3:
n.roleName = '老师'
break
case 4:
n.roleName = '学生'
break
}
})
if(this.roleList.length > 1) {
this.roleDialog = true
}else{
this.roleId = this.roleList[0].roleId
this.submitForm(form)
}
})
.catch(res => {});
},
updateInfo(data){
this.loginForm.username = data.username
this.loginForm.password = data.password
},
roleSure(form){
if(this.roleId){
this.submitForm(form)
}else{
util.errorMsg('请选择角色!')
}
},
submitForm(form) {
this.$refs[form].validate(valid => {
if (valid) {
let data = {
roleId: this.roleId,
userId: this.userId,
schoolId: this.schoolId
}
this.$get(this.api.logins,data).then(res => {
this.$post(this.api.updateLogInNumber,{userId: this.userId}).then(res => {}).catch(res => {})
let data = res.message.user
util.local.set(Setting.tokenKey,data.token,Setting.tokenExpires)
this.setInfo({
userId: this.userId,
roleId: this.roleId,
studentId: this.studentId,
schoolId: this.schoolId,
avatar: data.userAvatars,
userName: data.userName,
dataTime: data.dataTime,
})
util.successMsg('登录成功')
let redirect = decodeURIComponent(this.$route.query.redirect || '/index')
this.$router.replace(redirect)
}).catch(res => {});
}
});
},
cancleRoleDia() {
this.roleId = ''
this.roleDialog = false
},
toReg(status) {
this.isReg = status
},
forget(){
this.forgetVisible = true
},
emailCountdown(){
let count = 60
if(!this.emailTimer){
this.emailDisabled = true
this.emailTimer = setInterval(() => {
if(count > 0){
count--
this.emailBtnText = `${count}秒后重试`
}else{
this.emailDisabled = false
clearInterval(this.emailTimer)
this.emailTimer = null
this.emailBtnText = `发送验证码`
}
},1000)
}
},
phoneCountdown(){
let count = 60
if(!this.phoneTimer){
this.phoneDisabled = true
this.phoneTimer = setInterval(() => {
if(count > 0){
count--
this.phoneBtnText = `${count}秒后重试`
}else{
this.phoneDisabled = false
clearInterval(this.phoneTimer)
this.phoneTimer = null
this.phoneBtnText = `发送验证码`
}
},1000)
}
},
closeForget(){
this.phoneCode = ''
this.emailCode = ''
this.userId = ''
this.newPassword = ''
},
sendEmailCode(){
if(!this.email) return util.warningMsg('请输入邮箱')
if(!/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(this.email)) return util.warningMsg('请输入正确的邮箱')
let data = {
email: this.email
}
this.$get(this.api.findPasswordByEmail,data).then(res => {
if(res.errmessage == 'success'){
util.successMsg('发送成功')
this.emailCountdown()
this.userId = res.data.userId
this.emailOpener = res.data.opener
}
}).catch(res => {})
},
sendPhoneCode(){
if(!this.phone) return util.warningMsg('请输入手机号')
if(!/^1[3456789]\d{9}$/.test(this.phone)) return util.warningMsg('请输入正确的手机号')
let data = {
phone: this.phone
}
this.$get(this.api.findPasswordByPhone,data).then(res => {
if(res.errmessage == 'success'){
util.successMsg('发送成功')
this.phoneCountdown()
this.userId = res.data.userId
this.phoneOpener = res.data.opener
}
}).catch(res => {})
},
async updatePassword(type){
if(type == 1){
if(!this.phone) return util.warningMsg('请输入手机号')
if(!/^1[3456789]\d{9}$/.test(this.phone)) return util.warningMsg('请输入正确的手机号')
if(!this.phoneCode) return util.warningMsg('请输入验证码')
}else{
if(!this.email) return util.warningMsg('请输入邮箱')
if(!/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(this.email)) return util.warningMsg('请输入正确的邮箱')
if(!this.emailCode) return util.warningMsg('请输入验证码')
}
if(!this.newPassword) return util.warningMsg('请输入新密码')
let checkData = {
code: type == 1 ? this.phoneCode : this.emailCode,
opener: type == 1 ? this.phoneOpener : this.emailOpener
}
let checkRes = await this.$post(this.api.checkCode,checkData)
if(checkRes.errmessage == 'success'){
let resetData = {
userId: this.userId,
password: this.newPassword
}
let resetRes = await this.$post(this.api.resetPassword,resetData)
if(resetRes.errmessage == 'success'){
util.successMsg('重置成功')
this.forgetVisible = false
}
}
},
switchType(type){
this.phoneReset = type
}
},
};
</script>
<style scoped lang="scss">
.wrap {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
.header {
width: 100%;
height: 60px;
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 18px;
box-shadow: 1px 1px 3px 2px #ececec;
.logo {
width: 150px;
margin-left: 20px;
}
}
.bg{
display: flex;
justify-content: space-between;
align-items: center;
height: calc(100% - 116px);
.left{
position: relative;
width: 40%;
height: 100%;
background: url(../../../assets/img/bg_2.png) 0 0/100% 100% no-repeat;
.text{
position: absolute;
top: 35%;
left: 15%;
color: #fff;
font-size: 46px;
font-weight: bold;
p:first-child{
margin-bottom: 20px;
}
}
}
.right{
width: 50%;
height: 100%;
background: url(../../../assets/img/bg_1.png) center center/80% auto no-repeat;
}
}
/deep/.right-form{
position: absolute;
top: 47%;
right: 12%;
transform: translateY(-50%);
width: 30%;
.logo{
width: 100%;
margin-bottom: 40px;
}
.form{
padding: 50px 20px 20px;
background-color: #fff;
border-radius: 16px;
box-sizing: border-box;
box-shadow: 0 1px 20px rgba(146,120,255,0.3);
}
.back{
position: absolute;
top: 20px;
left: 20px;
font-size: 24px;
color: #9278ff;
cursor: pointer;
&:hover{
opacity: .8;
}
}
.el-tabs__nav-scroll{
display: flex;
justify-content: center;
}
h2{
padding-bottom: 10px;
font-size: 20px;
font-weight: 400;
color: #8F73FF;
text-align: center;
border-bottom: 1px solid #f3f3f3;
}
.el-form{
width: 70%;
margin: 30px auto 0;
.label{
line-height: 1.8;
color: #929292;
}
/deep/.el-input__inner{
height: 46px;
padding: 0 23px;
line-height: 46px;
border: 1px solid #E5E5E5;
border-radius: 8px !important;
}
/deep/.el-form-item__error{
top: 105%;
left: auto;
right: 0;
color: #FFA94E;
}
.submit{
width: 100%;
height: 48px;
margin-top: 40px;
line-height: 48px;
padding: 0;
font-size: 18px;
background-color: #9278ff;
border-radius: 6px;
border: 0;
}
}
}
}
.switch{
span{
cursor: pointer;
color: #9076FF;
}
}
.links{
width: 70%;
margin: 20px auto 0;
text-align: right;
}
.ques{
color: #9278ff;
font-size: 14px;
}
.forget{
color: #ffa94e;
font-size: 14px;
}
</style>

@ -0,0 +1,237 @@
<template>
<div>
<!-- <h2><div class="back" @click="toLogin"><i class="el-icon-arrow-left">返回</i></div> 学生注册</h2> -->
<h2>账号注册</h2>
<el-form class="register" :model="regForm" :rules="regRules" ref="reg" label-width="0px">
<div class="line">
<el-form-item prop="userName">
<p class="label">*学生姓名</p>
<el-input v-model="regForm.userName" placeholder="姓名"></el-input>
</el-form-item>
<el-form-item prop="workNumber" style="margin-right: 5%">
<p class="label">学生学号</p>
<el-input v-model="regForm.workNumber" placeholder="学生学号" @change="worknumberChange"></el-input>
</el-form-item>
<el-form-item prop="phone">
<p class="label">*手机号</p>
<el-input v-model="regForm.phone" placeholder="手机号" maxlength="11" @change="phoneChange"></el-input>
</el-form-item>
</div>
<p class="label">*学校</p>
<div class="line">
<el-form-item prop="provinceId">
<p class="prop">省份</p>
<el-select v-model="regForm.provinceId" placeholder="省份" @change="getCity">
<el-option
v-for="item in provinceList"
:key="item.value"
:label="item.provinceName"
:value="item.provinceId"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="cityId" style="margin-right: 5%">
<p class="prop">城市</p>
<el-select v-model="regForm.cityId" placeholder="城市" @change="getSchoolData">
<el-option
v-for="item in cityList"
:key="item.value"
:label="item.cityName"
:value="item.cityId"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="schoolAppellationId">
<p class="prop">学校</p>
<el-select v-model="regForm.schoolAppellationId" placeholder="学校名称">
<el-option v-for="(item,index) in schoolList" :key="index" :label="item.schoolName" :value="item.schoolId"></el-option>
</el-select>
</el-form-item>
</div>
<!-- <div class="line">
<el-form-item prop="phone">
<p class="label">手机号</p>
<el-input v-model="regForm.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item style="margin-right: 5%">
<button type="button" class="code-btn">发送验证码</button>
</el-form-item>
<el-form-item prop="code">
<el-input v-model="regForm.code" placeholder="输入验证码"></el-input>
</el-form-item>
</div> -->
<div class="line">
<el-form-item prop="password">
<p class="label">*密码设置</p>
<el-input type="password" v-model="regForm.password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item prop="rePassword">
<el-input type="password" v-model="regForm.rePassword" placeholder="请再次输入密码" @keyup.enter.native="registerForm"></el-input>
</el-form-item>
</div>
<el-button class="submit" type="primary" @click="registerForm">注册</el-button>
</el-form>
</div>
</template>
<script>
export default {
data: function() {
return {
regForm: {
userName: '',
workNumber: '',
provinceId: '',
cityId: '',
schoolAppellationId: '',
phone: '',
password: '',
rePassword: '',
roleId: 4,
schoolId: this.$config.schoolId
},
regRules: {
userName: [{ required: true, message: '请输入学生姓名', trigger: 'blur' }],
workNumber: [{ required: true, message: '请输入学生学号', trigger: 'blur' }],
provinceId: [{ required: true, message: '请选择省份', trigger: 'change' }],
cityId: [{ required: true, message: '请选择城市', trigger: 'change' }],
schoolAppellationId: [{ required: true, message: '请选择学校', trigger: 'change' }],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ pattern: /^.{6,}$/, message: '请输入6位数以上的密码', trigger: 'blur' }
],
rePassword: [
{ required: true, message: '请再次输入密码', trigger: 'blur' },
{ pattern: /^.{6,}$/, message: '请输入6位数以上的密码', trigger: 'blur' }
]
},
provinceList: this.$store.state.provinceList, //
cityList: [], //
schoolList: [],
phoneRepeat: false,
workNumberReapeat: false
};
},
mounted() {
this.getProvince()
this.getSchoolData()
},
methods: {
getProvince(){
this.$get(this.api.queryProvince).then(res => {
this.provinceList = res.message
this.$store.commit("provinceData", { provinceList : this.provinceList});
}).catch(res => {});
},
//
getCity(){
this.regForm.cityId = ''
this.$get(this.api.queryCity,{provinceId: this.regForm.provinceId}).then(res => {
this.cityList = res.message
this.getSchoolData()
}).catch(res => {})
},
//
getSchoolData(){
this.regForm.schoolAppellationId = ''
this.$get(this.api.querySchoolData,{provinceId: this.regForm.provinceId,cityId: this.regForm.cityId,schoolName: ''}).then(res => {
this.schoolList = res.message
}).catch(res => {});
},
registerForm() {
this.$refs.reg.validate(valid => {
if (valid) {
if(this.phoneRepeat) return util.warningMsg('该手机号已存在')
if(this.workNumberReapeat) return util.warningMsg('该学生学号已存在')
if(this.regForm.password !== this.regForm.rePassword) return util.warningMsg('两次输入的密码不一致,请重新输入')
let data = this.regForm
data.account = data.phone
data.uniqueIdentificationAccount = new Date().getTime()
this.$post(`${this.api.save}?workNumber=${this.regForm.workNumber}`,data).then(res => {
util.successMsg('注册成功')
this.$emit('update:isReg',false)
this.$emit('updateInfo',{username: this.regForm.phone,password: this.regForm.password})
this.$refs.reg.resetFields()
}).catch(res => {});
} else {
// util.errorMsg('');
return false;
}
});
},
async phoneChange(){
let res = await this.$get(this.api.queryPhone, { phone: this.regForm.phone });
if(res.message.length != 0){
util.warningMsg('该手机号已存在');
this.phoneRepeat = true
}else{
this.phoneRepeat = false
}
},
async worknumberChange(){
let res = await this.$get(this.api.queryWorkNumberIsExist, {
workNumber: this.regForm.workNumber,
roleId: 4,
schoolAppellationId: this.regForm.schoolAppellationId
});
if(JSON.stringify(res.message) != '{}'){
util.warningMsg('该学生学号已存在');
this.workNumberReapeat = true
}else{
this.workNumberReapeat = false
}
},
toLogin() {
this.$emit('update:isReg',false)
}
},
};
</script>
<style scoped lang="scss">
.wrap {
.form{
.register{
width: 90% !important;
.line{
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.el-form-item{
&:first-child{
margin-right: 5%;
}
}
.label{
margin-bottom: 0;
}
.prop{
color: #929292;
}
.code-btn{
min-width: 120px;
height: 46px;
padding: 0 10px;
line-height: 46px;
color: #fff;
font-size: 14px;
border-radius: 23px;
border: 0;
background-color: #105cb2;
}
.submit{
margin-bottom: 20px;
}
}
}
}
</style>

@ -0,0 +1,369 @@
<template>
<div>
<div class="page">
<h6 class="p-title">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<label>考核时间</label>
<el-radio-group size="small" v-model="form.month" @change="getData">
<el-radio v-for="(item,index) in dateList" :key="index" :label="item.id" border>{{item.name}}</el-radio>
</el-radio-group>
<el-date-picker size="small" v-model="date" align="right" unlink-panels type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" format="yyyy-MM-dd" value-format="yyyy-MM-dd" clearable></el-date-picker>
</li>
<li>
<label>实验状态</label>
<el-select size="small" v-model="form.status" placeholder="请选择实验状态" @change="getData">
<el-option v-for="(item,index) in statusList" :key="index" :label="item.name" :value="item.value"></el-option>
</el-select>
</li>
<li>
<el-input size="small" placeholder="请输入实验班级/考核名称" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</li>
</ul>
</div>
<el-table :data="listData" class="table" stripe header-align="center" :row-key="getRowKeys">
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (page - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="experimentalName" label="考核名称" align="center">
</el-table-column>
<el-table-column prop="experimentalClassName" label="实验班级" align="center">
</el-table-column>
<el-table-column prop="experimentalNumber" label="实验人数" align="center"></el-table-column>
<el-table-column prop="experimentDuration" label="考试时长" align="center">
</el-table-column>
<el-table-column prop="creationTime" label="创建时间" align="center">
</el-table-column>
<el-table-column prop="startTime" label="起始时间" align="center">
</el-table-column>
<el-table-column prop="stopTime" label="结束时间" align="center">
</el-table-column>
<el-table-column label="倒计时" align="center">
<template slot-scope="scope">
<span v-countdown="scope.row.surplusTime">{{scope.row.surplusTime}}</span>
</template>
</el-table-column>
<el-table-column label="实验状态" align="center">
<template slot-scope="scope">
<span class="ellipsis">{{status[scope.row.status]}}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button v-if="scope.row.status == 3 && !scope.row.done" type="text" disabled>未参加</el-button>
<el-button v-if="scope.row.status != 3 && !scope.row.done" type="text" @click="entry(scope.row)" :disabled="scope.row.status != 2">进入</el-button>
<el-button v-if="scope.row.status == 2 && scope.row.done" type="text" disabled>已提交</el-button>
<el-button v-if="scope.row.status == 3 && scope.row.done" type="text" @click="show(scope.row)">查看成绩</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="totals" @current-change="handleCurrentChange" :current-page="page"></el-pagination>
</div>
</div>
<el-dialog title="请输入邀请码" :visible.sync="icVisible" width="30%" @close="closeIc" center :close-on-click-modal="false">
<el-input v-model="invitationCode" placeholder="邀请码" maxlength="6"></el-input>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="saveIc"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapState,mapActions } from 'vuex'
import Setting from '@/setting'
import util from '@/libs/util'
export default {
name: 'ass',
data() {
return {
host: Setting.host,
status: ['','待开始','进行中','已完成'],
statusList: [{
name:'不限',
value: 0
},{
name:'待开始',
value: 1
},{
name:'进行中',
value: 2
},{
name:'已完成',
value: 3
}],
listData: [],
date: [],
form: {
month:'',
startTime: '',
endTime: '',
status: 0,
},
keyword: '',
dateList: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '近一个月'
},
{
id: 3,
name: '近三个月'
},
{
id: 6,
name: '近六个月'
}
],
page: 1,
pageSize: 10,
totals: 0,
icVisible: false,
invitationCode: '',
searchTimer: null,
timerList: [],
curRow: {}
};
},
computed: {
...mapState('user', [
'userId','schoolId','studentId','userName'
]),
},
watch: {
'form.month': function(val){
if(val){
let unit = 24 * 60 * 60 * 1000
this.date = [util.formatDate('yyyy-MM-dd',new Date(new Date().getTime() - unit * 30 * val)),util.formatDate('yyyy-MM-dd',new Date(new Date().getTime() + unit))]
}else{
this.date = []
}
},
date: function(val){
if(val){
this.form.startTime = val[0]
this.form.endTime = val[1]
}else{
this.form.startTime = ''
this.form.endTime = ''
}
this.getData()
},
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.getData()
},500)
}
},
mounted() {
this.getData()
this.$once('hook:beforeDestroy', function () {
this.timerList.forEach((n,k) => {
clearInterval(n)
})
this.timerList = []
})
},
directives: {
countdown: {
bind: function(el,binding,vnode) {
let that = vnode.context
let time = binding.value
let timer = setInterval(() => {
let timeList = time.split(':')
let total = Number.parseInt(timeList[0] * 60 * 60) + Number.parseInt(timeList[1] * 60) + Number.parseInt(timeList[2])
if(total > 0){
--total
let hours = Math.floor(total / (60 * 60))
let minutes = Math.floor(total % (60 * 60) / 60)
let seconds = Math.floor(total % (60 * 60) % 60)
time = `${that.core.formateTime(hours)}:${that.core.formateTime(minutes)}:${that.core.formateTime(seconds)}`
}else{
clearInterval(timer)
}
el.innerHTML = time
},1000)
that.timerList.push(timer)
}
}
},
methods: {
getData() {
let data = {
schoolId: this.schoolId,
month: this.form.month,
startTime: this.form.startTime,
endTime: this.form.endTime,
condition: this.keyword,
status: this.form.status,
page: this.page,
size: this.pageSize,
rowId: '',
projectId: ''
}
this.$get(this.api.userRecord,data).then(res => {
let list = res.page.list
this.totals = res.page.totalCount
let doneNum = 0
let recordList = []
for(let i = 1; i < 11; i++){
if(i != 2 && i != 3){
this.$get(this.api.experimentRecord, {
userid: this.userId,
page: 1,
size: 10000,
systemId: i
}).then(res => {
doneNum++
recordList = recordList.concat(res.data.list)
if(doneNum == 8){
list.map(n => {
let same = recordList.find(e => e.id == n.id)
if(same){
n.done = true
n.recordid = same.recordid
n.reportId = same.reportId
}
})
this.listData = list
}
}).catch(err => {})
}
}
}).catch(res => {})
},
add(){
this.$store.commit("listData", { customer_id : ''});
this.$router.push('/addclass');
},
edit(row){
this.$store.commit("listData", { customer_id : row.customerId });
this.$router.push('/addcustomer');
},
getRowKeys(row) {
return row.customerId;
},
onSearch(){
this.page = 1
this.getData()
},
handleCurrentChange(val) {
this.page = val
this.getData()
},
entry(row) {
if(row.status == 1){
return util.warningMsg('该实验尚未开始')
}else if(row.status == 3){
return util.warningMsg('该实验已经结束')
}else{
this.curRow = row
if(row.isCode == 1){
this.goSubSystem()
}else{
this.$get(this.api.checkInvitationCode,{
userId: this.userId,
id: row.id
}).then(res => {
if(res.errmessage == 'false'){
this.icVisible = true
}else{
this.goSubSystem()
}
}).catch(res => {});
}
}
},
show(row) {
this.$router.push(`/showExperiment?id=${row.id}&recordId=${row.recordid}&reportId=${row.reportId}`)
},
saveIc() {
if(!this.invitationCode) return util.warningMsg('请输入邀请码')
if(!this.invitationCode || String(this.invitationCode).length < 6 || isNaN(this.invitationCode)) return util.warningMsg('请输入6位纯数字邀请码')
let data = {
id: this.curRow.id,
userId: this.userId,
invitationCode: Number(this.invitationCode)
}
this.$post(this.api.joinPractice,data).then(res => {
if(res.errmessage == 'success') {
util.successMsg('验证成功!')
this.icVisible = false
setTimeout(() => {
this.goSubSystem()
},1000)
}
}).catch(res => {});
},
closeIc() {
this.invitationCode = ''
},
goback() {
this.$router.back()
},
goSubSystem(){
let host = this.host
util.cookies.set("assessmentId",this.curRow.id)
util.cookies.set("studentId",this.studentId)
util.cookies.set("userId",this.userId)
util.cookies.set("projectId",this.curRow.projectId)
util.cookies.set("startTime",this.curRow.startTime)
util.cookies.set("stopTime",this.curRow.stopTime)
let systemId = this.curRow.systemId
let href = ''
switch(systemId){
case 1:
href = `${host}pyTrials/#/`
break;
case 4:
href = `${host}pyFinance/#/`
break;
case 5:
href = `${host}pyProjects/#/`
break;
case 6:
href = `${host}pyRandom/#/`
break;
case 7:
href = `${host}pyQuantification/#/`
break;
case 8:
href = `${host}pyAnalysis/#/`
break;
case 9:
href = `${host}pyDataclean/#/`
break;
case 10:
href = `${host}pyAcquisition/#/`
break;
}
if(!href) return util.errorMsg('该考核非Python考核,请选择其他考核')
location.href = href
// location.href = 'http://192.168.31.154:8080/'
},
}
};
</script>
<style lang="scss" scoped>
/deep/.el-tabs__nav-wrap::after{
display: none;
}
.no-mb /deep/.el-form-item{
margin-bottom: 0;
}
.el-radio.is-bordered+.el-radio.is-bordered{
margin-left: 0;
}
</style>

@ -0,0 +1,59 @@
<template>
<div class="error-page">
<div class="error-code">4<span>0</span>3</div>
<div class="error-desc">啊哦~ 你没有权限访问该页面哦</div>
<div class="error-handle">
<router-link to="/">
<el-button type="primary" size="large" @click="toIndex">返回首页</el-button>
</router-link>
<el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
</div>
</div>
</template>
<script>
export default {
methods: {
toIndex(){
this.$router.push('/')
},
goBack(){
this.$router.go(-1);
}
}
}
</script>
<style scoped>
.error-page{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
height: 100%;
background: #f3f3f3;
box-sizing: border-box;
}
.error-code{
line-height: 1;
font-size: 250px;
font-weight: bolder;
color: #f02d2d;
}
.error-code span{
color: #00a854;
}
.error-desc{
font-size: 30px;
color: #777;
}
.error-handle{
margin-top: 30px;
padding-bottom: 200px;
}
.error-btn{
margin-left: 100px;
}
</style>

@ -0,0 +1,59 @@
<template>
<div class="error-page">
<div class="error-code">4<span>0</span>4</div>
<div class="error-desc">啊哦~ 你所访问的页面不存在</div>
<div class="error-handle">
<router-link to="/">
<el-button type="primary" size="large" @click="toIndex">返回首页</el-button>
</router-link>
<el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
</div>
</div>
</template>
<script>
export default {
methods: {
toIndex(){
this.$router.push('/')
},
goBack(){
this.$router.go(-1);
}
}
}
</script>
<style scoped>
.error-page{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
height: 100%;
background: #f3f3f3;
box-sizing: border-box;
}
.error-code{
line-height: 1;
font-size: 250px;
font-weight: bolder;
color: #2d8cf0;
}
.error-code span{
color: #00a854;
}
.error-desc{
font-size: 30px;
color: #777;
}
.error-handle{
margin-top: 30px;
padding-bottom: 200px;
}
.error-btn{
margin-left: 100px;
}
</style>

@ -0,0 +1,46 @@
<template>
<section class="main">
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-lx-global"></i> {{$t('i18n.breadcrumb')}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="container">
<span>{{$t('i18n.tips')}}</span>
<el-button type="primary" @click="$i18n.locale = $i18n.locale === 'zh'?'en':'zh';">{{$t('i18n.btn')}}</el-button>
<div class="list">
<h2>{{$t('i18n.title1')}}</h2>
<p>{{$t('i18n.p1')}}</p>
<p>{{$t('i18n.p2')}}</p>
<p>{{$t('i18n.p3')}}</p>
</div>
<h2>{{$t('i18n.title2')}}</h2>
<div>
<i18n path="i18n.info" tag="p">
<a place="action" href="https://element.eleme.cn/2.0/#/zh-CN/component/i18n">{{ $t('i18n.value') }}</a>
</i18n>
</div>
</div>
</section>
</template>
<script>
export default {
data(){
return {
}
}
}
</script>
<style scoped>
.list{
padding: 30px 0;
}
.list p{
margin-bottom: 20px;
}
a{
color: #cb221c;
}
</style>

@ -0,0 +1,225 @@
<template>
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-lx-emoji"></i> 自定义图标</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="container">
<h2>使用方法</h2>
<p style="line-height: 50px;">
直接通过设置类名为 el-icon-lx-iconName 来使用即可例如{{iconList.length}}个图标
</p>
<p class="example-p">
<i class="el-icon-lx-redpacket_fill" style="font-size: 30px;color: #ff5900"></i>
<span>&lt;i class=&quot;el-icon-lx-redpacket_fill&quot;&gt;&lt;/i&gt;</span>
</p>
<p class="example-p">
<i class="el-icon-lx-weibo" style="font-size: 30px;color:#fd5656"></i>
<span>&lt;i class=&quot;el-icon-lx-weibo&quot;&gt;&lt;/i&gt;</span>
</p>
<p class="example-p">
<i class="el-icon-lx-emojifill" style="font-size: 30px;color: #ffc300"></i>
<span>&lt;i class=&quot;el-icon-lx-emojifill&quot;&gt;&lt;/i&gt;</span>
</p>
<br>
<h2>图标</h2>
<div class="search-box">
<el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
</div>
<ul>
<li class="icon-li" v-for="(item,index) in list" :key="index">
<div class="icon-li-content">
<i :class="`el-icon-lx-${item}`"></i>
<span>{{item}}</span>
</div>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data: function(){
return {
keyword: '',
iconList: [
'attentionforbid',
'attentionforbidfill',
'attention',
'attentionfill',
'tag',
'tagfill',
'people',
'peoplefill',
'notice',
'noticefill',
'mobile',
'mobilefill',
'voice',
'voicefill',
'unlock',
'lock',
'home',
'homefill',
'delete',
'deletefill',
'notification',
'notificationfill',
'notificationforbidfill',
'like',
'likefill',
'comment',
'commentfill',
'camera',
'camerafill',
'warn',
'warnfill',
'time',
'timefill',
'location',
'locationfill',
'favor',
'favorfill',
'skin',
'skinfill',
'news',
'newsfill',
'record',
'recordfill',
'emoji',
'emojifill',
'message',
'messagefill',
'goods',
'goodsfill',
'crown',
'crownfill',
'move',
'add',
'hot',
'hotfill',
'service',
'servicefill',
'present',
'presentfill',
'pic',
'picfill',
'rank',
'rankfill',
'male',
'female',
'down',
'top',
'recharge',
'rechargefill',
'forward',
'forwardfill',
'info',
'infofill',
'redpacket',
'redpacket_fill',
'roundadd',
'roundaddfill',
'friendadd',
'friendaddfill',
'cart',
'cartfill',
'more',
'moreandroid',
'back',
'right',
'shop',
'shopfill',
'question',
'questionfill',
'roundclose',
'roundclosefill',
'roundcheck',
'roundcheckfill',
'global',
'mail',
'punch',
'exit',
'upload',
'read',
'file',
'link',
'full',
'group',
'friend',
'profile',
'addressbook',
'calendar',
'text',
'copy',
'share',
'wifi',
'vipcard',
'weibo',
'remind',
'refresh',
'filter',
'settings',
'scan',
'qrcode',
'cascades',
'apps',
'sort',
'searchlist',
'search',
'edit'
]
}
},
computed: {
list(){
return this.iconList.filter((item) => {
return item.indexOf(this.keyword) !== -1;
})
}
}
}
</script>
<style scoped>
.example-p{
height: 45px;
display: flex;
align-items: center;
}
.search-box{
text-align: center;
margin-top: 10px;
}
.search{
width: 300px;
}
ul,li{
list-style: none;
}
.icon-li{
display: inline-block;
padding: 10px;
width: 120px;
height: 120px;
}
.icon-li-content{
display: flex;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
}
.icon-li-content i{
font-size: 36px;
color: #606266;
}
.icon-li-content span{
margin-top: 10px;
color: #787878;
}
</style>

@ -0,0 +1,31 @@
<template>
<div class="wrap">
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'index',
data() {
return {
}
},
mounted() {
this.getHot()
},
methods: {
getData(){
},
}
};
</script>
<style lang="scss" scoped>
.wrap{
}
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save