提交代码

master
e 3 years ago
parent fdd5c5ce14
commit 4d0daaae61
  1. 3
      .browserslistrc
  2. 22
      .gitignore
  3. 6
      .prettierrc
  4. 21
      LICENSE
  5. 5
      babel.config.js
  6. 13428
      package-lock.json
  7. 38
      package.json
  8. 5
      postcss.config.js
  9. 18
      public/index.html
  10. 24
      src/App.vue
  11. 167
      src/api/index.js
  12. BIN
      src/assets/img/avg.png
  13. BIN
      src/assets/img/bind.png
  14. BIN
      src/assets/img/cup.png
  15. BIN
      src/assets/img/date.png
  16. BIN
      src/assets/img/edit.png
  17. BIN
      src/assets/img/icon-xiangyou.png
  18. BIN
      src/assets/img/icon-yigouxuan.png
  19. BIN
      src/assets/img/icon_.png
  20. BIN
      src/assets/img/icon_1.png
  21. BIN
      src/assets/img/idcard.png
  22. BIN
      src/assets/img/images/back_02.png
  23. BIN
      src/assets/img/img.jpg
  24. BIN
      src/assets/img/login-bg.png
  25. BIN
      src/assets/img/login-input.png
  26. BIN
      src/assets/img/logo-hh.png
  27. BIN
      src/assets/img/logo.png
  28. BIN
      src/assets/img/open.png
  29. BIN
      src/assets/img/person/bg.png
  30. BIN
      src/assets/img/person/manag.png
  31. BIN
      src/assets/img/person/user.png
  32. BIN
      src/assets/img/school.png
  33. BIN
      src/assets/img/select.png
  34. BIN
      src/assets/img/student1.png
  35. BIN
      src/assets/img/student2.png
  36. BIN
      src/assets/img/student3.png
  37. BIN
      src/assets/img/student4.png
  38. BIN
      src/assets/img/total.png
  39. 124
      src/components/pdf/index.vue
  40. 206
      src/components/quill/index.vue
  41. 16
      src/components/quill/options.js
  42. 30
      src/i18n/index.js
  43. 43
      src/layouts/footer/index.vue
  44. 84
      src/layouts/header/index.vue
  45. 66
      src/layouts/home/index.vue
  46. 127
      src/layouts/navbar/index.vue
  47. 25
      src/libs/auth/generateBtnPermission.js
  48. 6
      src/libs/bus.js
  49. 10
      src/libs/random_str.js
  50. 16
      src/libs/resize/index.js
  51. 32
      src/libs/route/addRoutes.js
  52. 26
      src/libs/route/generateRoutes.js
  53. 6
      src/libs/route/resetRouter.js
  54. 43
      src/libs/util.cookies.js
  55. 83
      src/libs/util.db.js
  56. 184
      src/libs/util.js
  57. 45
      src/main.js
  58. 11
      src/mixins/app.js
  59. 8
      src/mixins/setBackground/index.js
  60. 201
      src/pages/account/login/index.vue
  61. 299
      src/pages/achievement/ass/index.vue
  62. 368
      src/pages/achievement/edit/index.vue
  63. 276
      src/pages/achievement/list/index.vue
  64. 419
      src/pages/achievement/show/index.vue
  65. 304
      src/pages/achievement/teach/index.vue
  66. 297
      src/pages/achievement/vir/index.vue
  67. 492
      src/pages/assessment/add/index.vue
  68. 389
      src/pages/assessment/list/index.vue
  69. 631
      src/pages/evaluation/list/index.vue
  70. 59
      src/pages/exception/error/403/index.vue
  71. 59
      src/pages/exception/error/404/index.vue
  72. 46
      src/pages/exception/i18n/index.vue
  73. 225
      src/pages/exception/icon/index.vue
  74. 1075
      src/pages/project/add/index.vue
  75. 393
      src/pages/project/list/index.vue
  76. 1361
      src/pages/setting/person/index.vue
  77. 527
      src/pages/student/list/index.vue
  78. 61
      src/pages/system/list/index.vue
  79. 307
      src/pages/system/list/role.vue
  80. 864
      src/pages/system/list/staff.vue
  81. 363
      src/pages/system/list/staffSide.vue
  82. 251
      src/pages/system/list/stafftree.vue
  83. 1
      src/plugins/aliplayer/aliplayer-min.css
  84. 2
      src/plugins/aliplayer/aliplayer-min.js
  85. 25
      src/plugins/auth/index.js
  86. 12
      src/plugins/filters/index.js
  87. 14
      src/plugins/index.js
  88. 140
      src/plugins/requests/index.js
  89. 18
      src/plugins/throttle/index.js
  90. 22
      src/router/index.js
  91. 43
      src/router/modules/achievement.js
  92. 29
      src/router/modules/assessment.js
  93. 23
      src/router/modules/evaluation.js
  94. 29
      src/router/modules/project.js
  95. 23
      src/router/modules/setting.js
  96. 23
      src/router/modules/student.js
  97. 23
      src/router/modules/system.js
  98. 27
      src/router/permission.js
  99. 82
      src/router/routes.js
  100. 21
      src/setting.env.js
  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'
]
}

13428
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,38 @@
{
"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",
"js-cookie": "^2.2.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.14.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,167 @@
import Setting from '@/setting'
// let host = 'http://192.168.31.125:9090'//林
// let host = 'http://192.168.31.152:9090'//榕
let host = Setting.apiBaseURL
let uploadURL = Setting.upload.apiURL
let host1 = 'http://39.108.250.202:8080/'
export default {
fileupload: `${uploadURL}oss/manage/fileupload`,
logins: `${host}liuwanr/userInfo/adminLogins`, //登录
queryToken: `${host}liuwanr/userInfo/queryToken`,
updateLogInNumber: `${host}liuwanr/userInfo/updateLogInNumber`, //用户登录修改登录次数和登陆时间
uploadUserAvatars: `${host}liuwanr/userInfo/uploadUserAvatars`, //上传头像
queryProvince: `${host}liuwanr/province/queryProvince`, //查询省份
queryCity: `${host}liuwanr/city/queryCity`, //查询城市
querySchoolData: `${host}liuwanr/customer/querySchool`, //根据学校名称查询学校信息
queryAccountIsExist:`${host}liuwanr/userInfo/queryAccountIsExist`,//查询员工,学生账号是否存在接口
queryWorkNumberIsExist:`${host}liuwanr/userInfo/queryWorkNumberIsExist`,//查询学号、工号是否存在
querySchool: `${host}liuwanr/customer/querySchool`, //根据学校名称查询学校信息
queryPersonalCenter:`${host}liuwanr/personalCenter/queryPersonalCenter`,
addStaffPro: `${host}liuwanr/staffProfessionalArchitecture/addStaffProfessionalArchitecture`, //添加员工专业
queryStaffPro: `${host}liuwanr/staffProfessionalArchitecture/queryAllStaffProfessionalArchitecture`, //查询员工专业
deleteStaffPro: `${host}liuwanr/staffProfessionalArchitecture/deleteStaffProfessionalArchitecture`, //删除员工专业
deleteStaffGrade: `${host}liuwanr/staffGrade/deleteStaffGrade`, //删除员工部门
updateStaffPro: `${host}liuwanr/staffProfessionalArchitecture/updateStaffProfessionalArchitecture`, //编辑员工专业
queryStaffGrade: `${host}liuwanr/staffGrade/queryStaffGrade`, //查询员工部门
queryStaffGradeDetails: `${host}liuwanr/staffGrade/queryStaffGradeDetails`, //查询员工部门详情
addStaffGrade: `${host}liuwanr/staffGrade/addStaffGrade`, //新增员工部门
updateStaffGrade: `${host}liuwanr/staffGrade/updateStaffGrade`, //编辑员工部门
queryCourseDiscipline: `${host}liuwanr/course/queryCourseDiscipline`, //查询课程学科
queryCourseProfessionalClass: `${host}liuwanr/course/queryCourseProfessionalClass`, //查询专业类
queryCourseProfessional: `${host}liuwanr/course/queryCourseProfessional`, //查询专业
queryPhone: `${host}liuwanr/user/queryPhone`, //查询电话是否存在
queryEmail: `${host}liuwanr/user/queryEmail`, //查询邮箱是否存在
queryStaffPAN:`${host}liuwanr/staffProfessionalArchitecture/queryStaffPAN`,//查询员工专业是否存在
// 个人中心
userinfo:`${host}evaluation/tms/userInfo/userinfo`,
userinfoUpdate:`${host}evaluation/tms/userInfo/updateUser`,
sendEmailCode:`${host}evaluation/tms/user/sendEmailCode`,//发送邮箱验证码
bingEmail:`${host}evaluation/tms/user/bingEmail`,//邮箱验证并更新
sendPhoneCode:`${host}evaluation/tms/user/sendPhoneCode`,//发送手机验证码
bindPhone:`${host}evaluation/tms/user/bindPhone`,//校验手机验证码
examinePassword:`${host}evaluation/tms/user/examinePassword`,//更换密码
// 测评管理
list: `${host}evaluation/tms/questions/list`, //分页加条件查询试题信息
info: `${host}evaluation/tms/evaluationrules/info`, //测评规则信息的展示
update: `${host}evaluation/tms/evaluationrules/update`, //修改测评规则信息
delete: `${host}evaluation/tms/questions/delete`, //批量删除试题信息
questionsTemplate: `${host}template/试题导入模板.xlsx`, //excel模板文件下载
import: `${host}evaluation/tms/questions/import`, //通过excel批量导入
infoId: `${host}evaluation/tms/questions/info/`, //根据试题id查询试题详情信息
isenable: `${host}evaluation/tms/questions/isenable`, //是否禁用试题
save: `${host}evaluation/tms/questions/save`, //新增一道试题
questionsUpdate: `${host}evaluation/tms/questions/update`, //根据试题id修改试题信息
upload: `${host}evaluation/tms/questions/upload`, //excel模板文件上传
export_failure: `${host}evaluation/tms/questions/export_failure`, //导出导入失败的数据和失败原因
expDelete: `${host}evaluation/tms/exp/delete`, //删除实验教学
expList: `${host}evaluation/tms/exp/list`, //实验教学列表
expSave: `${host}evaluation/tms/exp/save`, //添加实验教学
expUpdate: `${host}evaluation/tms/exp/update`, //修改实验教学
expInfo: `${host}evaluation/tms/exp/getById/`, //实验教学详情
expCheck: `${host}evaluation/tms/exp/check`, //实验名称判重
getInvitationCode: `${host}evaluation/tms/exp/getInvitationCode`, //查询邀请码是否存在
expInfo1: `${host}evaluation/tms/exp/upload`, //实验教学提前结束
queryAllManagements: `${host}project/ProjectManagement/queryAllManagements`, //项目管理列表信息
queryManagements: `${host}project/ProjectManagement/queryManagements`, //项目管理列表信息
addRole: `${host}project/ProjectManagement/addRole`, //新增案例对象
avgValues: `${host}project/ProjectManagement/avgValues`, //平均分配分值
getByRoleId: `${host}project/ProjectManagement/getByRoleId`, //根据角色id查询信息
getByjudgmentPointsId: `${host}project/ProjectManagement/getByjudgmentPointsId`, //实验任务表格信息的展示
queryAllJudgmentPoints: `${host}project/ProjectManagement/queryAllJudgmentPoints`, //添加判分点面板的数据展示+条件筛选
getProjectId: `${host}project/ProjectManagement/getProjectId`, //根据项目管理id查询对应信息
updateProjectManagement: `${host}project/ProjectManagement/updateProjectManagement`, //编辑项目管理
addProjectManagement: `${host}project/ProjectManagement/addProjectManagement`, //添加项目管理
removeProjectManagement: `${host}project/ProjectManagement/removeProjectManagement`, //删除
getJudgmentPoints: `${host}project/ProjectManagement/getJudgmentPoints`, //复制项目获取数据
getZZJudgmentPoints: `${host}project/ProjectManagement/getZZJudgmentPoints`, //复制项目获取数据
updateRole: `${host}project/ProjectManagement/updateRole`, //修改实验数据—角色信息
isNameExistis: `${host}project/ProjectManagement/isNameExistis`, //项目名称是否存在
QueryPfdInformation: `${host}judgment/pointOfJudgement/queryPfdInformation`, //判分点详细信息
addProjectManagementTrad: `${host}project/ProjectManagement/newAddProjectManagement`,
getTrdingJudgmentPoints: `${host}project/ProjectManagement/getTrdingJudgmentPoints`,
updateProjectManagementTrad: `${host}project/ProjectManagement/newUpdateProjectManagement`,
enableProject: `${host}project/ProjectManagement/enable`,
QueryPointOfJudgement: `${host}judgment/pointOfJudgement/queryPointOfJudgement`, //判分点列表查询
queryUserIds:`${host}liuwanr/userInfo/queryUserIds`,
// 学生管理
addStudent: `${host}evaluation/tms/student/zzAddStudent`,
daleteStudent: `${host}evaluation/tms/student/daleteStudent`,
disableAccount: `${host}evaluation/tms/student/disableAccount`,
queryStudent: `${host}evaluation/tms/student/queryStudent`,
reSetPassword: `${host}evaluation/tms/student/reSetPassword`,
updateStudent: `${host}evaluation/tms/student/updateStudent`,
downloadStudent: `${host}evaluation/tms/student/download`,
uploadFile: `${host}evaluation/tms/student/uploadFile`,
export_failureStudent: `${host}evaluation/tms/student/export_failure`,
queryAccountStudent:`${host}evaluation/tms/student/queryAccount`,
studentTemplate:`${host}template/student.xlsx`,
// 员工管理
addStaff: `${host}evaluation/tms/system/addStaff`,
daleteBatchStaff: `${host}evaluation/tms/system/daleteBatchStaff`,
queryStaff: `${host}evaluation/tms/system/queryStaff`,
querystaffDetail: `${host}evaluation/tms/system/querystaffDetail`,
updateStaff: `${host}evaluation/tms/system/updateStaff`,
downloadStaff: `${host}evaluation/tms/system/download`,
export_failureStaff: `${host}evaluation/tms/system/export_failure`,
uploadFileStaff: `${host}evaluation/tms/system/uploadFile`,
queryAccountStaff:`${host}evaluation/tms/system/queryAccount`,
resetPwd:`${host}evaluation/tms/system/resetPwd`,
dalStaffByStaffGradeId:`${host}evaluation/tms/system/dalStaffByStaffGradeId`,
dalStaffByProfessionalId:`${host}evaluation/tms/system/dalStaffByProfessionalId`,
staffTemplate:`${host}template/staff.xlsx`,
// 角色权限
rolePermissionList:`${host}evaluation/sys-permission/rolePermissionList`,
saveRolePermission:`${host}evaluation/sys-permission/saveRolePermission`,
updateRolePermission:`${host}evaluation/sys-permission/updateRolePermission`,
delRolePermission:`${host}evaluation/sys-permission/delRolePermission`,
queryPermissionArrById:`${host}evaluation/sys-permission/queryPermissionArrById`,
roleTree:`${host}evaluation/sys-permission/tree`,
// 成绩管理
getImitationAchievement: `${host}evaluation/Achievement/getImitationAchievement`,
getTeachAchievement: `${host}evaluation/Achievement/getTeachAchievement`,
addReport: `${host}evaluation/Achievement/addReport`,
deleteReport: `${host}evaluation/Achievement/deleteReport`,
deleteReportById: `${host}evaluation/Achievement/deleteReportById`,
exportAchievement:`${host}evaluation/Achievement/exportAchievement`,
// queryAchievement:`${host}evaluation/Achievement/queryAchievement`,
queryAchievement:`${host}evaluation/Achievement/list`,
queryAchievementNew:`${host}evaluation/Achievement/newList`,
queryEvaluationReport:`${host}evaluation/Achievement/queryEvaluationReport`,
queryReport:`${host}evaluation/Achievement/queryReport`,
queryArchievement: `${host}evaluation/tms/classTech/queryExperimentalReport`, //查看教学实验报告
queryVirtualReport: `${host}evaluation/tms/classTech/queryVirtualReport`, //查看虚仿实验报告
// 教师评语
addComment: `${host}evaluation/comment/addComment`,
queryComment: `${host}evaluation/comment/queryComment`,
updateComment:`${host}evaluation/comment/updateComment`,
// 老师签名照
daleteSignature: `${host}evaluation/signature/daleteSignature`,
querySignature: `${host}evaluation/signature/querySignature`,
uploadSignature:`${host}evaluation/signature/uploadSignature`,
// 判分点
queryListTrading: `${host}judgment/tradingJudgmentPoints/query`,
queryDetailsTrading: `${host}judgment/tradingJudgmentPoints/queryDetails`,
// 科大
queryPoint: `${host}kdSys/queryPoint`,
querySubject: `${host}kdSys/querySubject`,
queryItem: `${host}kdSys/queryItem`,
// 川大
firstLevel: `${host1}sichuan/point/firstLevel`,
secondaryLevel: `${host1}sichuan/point/secondaryLevel`,
thirdLevel: `${host1}sichuan/point/thirdLevel`,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 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: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 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: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 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: 8.8 KiB

@ -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,206 @@
<template>
<div class="quill" ref="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
},
/*
* 原本的readOnly失效,对比其他项目发现是quill版本不同导致
* 使用props传入elseRead = 'true'手动隐藏工具栏
*/
elseRead:{
type:String,default:'false'
}
},
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
}
},
created(){
},
mounted () {
this.init();
//
if(this.elseRead==='true'){
let children = this.$refs.quill.children[0].style
children.padding = '0'
children.overflow = 'hidden'
children.height = '0'
children.borderTop = '0'
}
},
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;
}
}
.else{
.ql-toolbar.ql-snow{
height: 0;
overflow: hidden;
padding: 0;
border-top: 0;
}
}
</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,84 @@
<template>
<div class="header">
<img class="logo hh" v-if="isHh" src="@/assets/img/logo-hh.png" />
<img class="logo" v-else src="@/assets/img/logo.png" />
<div class="action">
<div class="user" @click="toPersonal">
<el-avatar :size="40" :src="avatar"></el-avatar>
<span class="m-l-10">{{userName}}</span>
</div>
<el-divider direction="vertical"></el-divider>
<el-button type="text" class="ml20" @click="logout">退出</el-button>
</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'
]),
...mapState('auth', [
'routes'
])
},
mounted(){
},
methods: {
...mapActions('user', [
'logout'
]),
toPersonal(){
this.$router.push('/setting/person')
},
},
};
</script>
<style lang="scss" scoped>
.header {
position: relative;
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
color: #333;
background-color: #fff;
.logo {
height: 50px;
margin-left: 20px;
&.hh{
width: 220px;
}
}
.action {
display: flex;
padding-right: 50px;
align-items: center;
.user{
display: inline-flex;
align-items: center;
cursor: pointer;
}
.el-button--text{
margin-left: 20px;
color: #333;
}
.el-divider{
width: 2px;
height: 15px;
margin-left: 20px;
background-color: #333;
}
}
}
</style>

@ -0,0 +1,66 @@
<template>
<div class="main">
<v-head></v-head>
<div class="layout">
<navbar></navbar>
<div class="content">
<transition name="move" mode="out-in">
<router-view class="view"></router-view>
</transition>
<el-backtop target=".content"></el-backtop>
</div>
<v-footer ref="footer"></v-footer>
</div>
</div>
</template>
<script>
import vHead from '../header'
import navbar from '../navbar'
import vFooter from '../footer'
import { mapState, mapActions } from 'vuex'
import util from '@/libs/util'
import Setting from '@/setting'
export default {
data() {
return {
};
},
components: {
vHead,
navbar,
vFooter
},
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%;
.content{
min-height: calc(100vh - 176px);
padding: 24px 24px 0;
}
}
</style>

@ -0,0 +1,127 @@
<template>
<div>
<el-menu class="sidebar-el-menu" :default-active="active" background-color="#324157" text-color="#bfcbd9" active-text-color="#9278FF" unique-opened mode="horizontal" router>
<template v-for="item in menus">
<template v-if="item.subs">
<el-submenu :index="item.index" :key="item.index">
<template slot="title">
<i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</template>
<template v-for="subItem in item.subs">
<el-submenu v-if="subItem.subs" :index="subItem.index" :key="subItem.index">
<template slot="title">{{ subItem.title }}</template>
<el-menu-item v-for="(threeItem,i) in subItem.subs" :key="i" :index="threeItem.index">{{ threeItem.title }}</el-menu-item>
</el-submenu>
<el-menu-item v-else :index="subItem.index" :key="subItem.index">{{ subItem.title }}</el-menu-item>
</template>
</el-submenu>
</template>
<template v-else>
<el-menu-item :index="item.index" :key="item.index">
<i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</el-menu-item>
</template>
</template>
</el-menu>
</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,
defaultMenus: [
{
icon: 'el-icon-takeaway-box',
index: '/assessment/list',
title: '考核管理'
},
{
icon: 'el-icon-collection',
index: '/achievement/list',
title: '成绩管理'
},
{
icon: 'el-icon-receiving',
index: '/evaluation/list',
title: '测评管理'
},
{
icon: 'el-icon-postcard',
index: '/project/list',
title: '实验项目管理'
},
{
icon: 'el-icon-user',
index: '/student/list',
title: '学生管理'
},
{
icon: 'el-icon-setting',
index: '/system/list',
title: '系统设置'
}
],
menus: [],
actives: {
dashboard: ['add'],
achievement: ['experiment','experimentVir','experimentTeach','addexperiment','addexperimentoptions','showExperiment','showExperimentoption','showExperimentoptions'],
project: ['addproject','program','programOption','programOptions'],
backstage: ['report']
}
};
},
computed: {
...mapState('auth', [
'routes'
])
},
watch: {
'$route'(to,from) {
let actives = this.actives
for(let i in this.actives){
if(actives[i].includes(this.$route.name)) this.active = `/${i}/list`
}
this.active = this.$route.path
}
},
created() {
this.initMenu()
},
methods: {
initMenu(){
if(Setting.dynamicRoute){
let routes = this.routes
let menus = []
this.defaultMenus.map(e => {
routes.find(n => n.path == e.index) && menus.push(e)
})
this.menus = menus
}else{
this.menus = this.defaultMenus
}
},
}
};
</script>
<style lang="scss" scoped>
.sidebar::-webkit-scrollbar {
width: 0;
}
.sidebar-el-menu:not(.el-menu--collapse) {
width: 100%;
}
.el-menu.el-menu--horizontal{
border-bottom: none;
}
.sidebar > ul {
height: 100%;
}
</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,184 @@
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 roleList = {
'1': '超级管理员',
'13': '管理员',
'14': '老师',
'4': '学生'
}
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)
}
},
// 传入字符串,返回去除[]后的字符串,因为通过get请求带入方括号的话会有问题
encodeStr(str) {
if(str.includes('[') || str.includes(']')){
let newStr = ''
for(let i of str){
if(i == '[' || i == ']'){
newStr += encodeURI(i)
}else{
newStr += i
}
}
return newStr
}
return str
},
// 成功提示
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})
},
// 传入roleId,返回角色名称
getRoleName(roleId){
return roleList[roleId] || '未知状态'
},
// 登录互踢
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,201 @@
<template>
<div class="wrap">
<div class="header">
<img class="logo hh" v-if="isHh" src="@/assets/img/logo-hh.png" />
<img class="logo" v-else src="@/assets/img/logo.png" />
</div>
<div class="main">
<div class="box">
<el-tabs v-model="type">
<el-tab-pane label="账号登录" name="0">
<el-form :model="param" :rules="rules" ref="param" label-width="0px" style="margin-top: 40px">
<el-form-item prop="username">
<el-input v-model="param.username" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
placeholder="请输入密码"
v-model="param.password"
@keyup.enter.native="submitForm('param')"
>
</el-input>
</el-form-item>
<el-button class="btn" type="primary" @click="submitForm('param')">马上登录</el-button>
</el-form>
</el-tab-pane>
<el-tab-pane label="手机号/邮箱登录" name="1">
<el-form :model="phoneParam" :rules="phoneRules" ref="phoneParam" label-width="0px" style="margin-top: 40px">
<el-form-item prop="userphone">
<el-input v-model="phoneParam.userphone" placeholder="请输入手机号/邮箱"></el-input>
</el-form-item>
<el-form-item prop="phonePassword">
<el-input
type="password"
placeholder="请输入密码"
v-model="phoneParam.phonePassword"
@keyup.enter.native="submitForm('phoneParam')"
>
</el-input>
</el-form-item>
<el-button class="btn" type="primary" @click="submitForm('phoneParam')">马上登录</el-button>
</el-form>
</el-tab-pane>
</el-tabs>
</div>
</div>
<v-footer class="footer"></v-footer>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import vFooter from '@/layouts/footer'
import util from '@/libs/util'
import Setting from '@/setting'
export default {
data: function() {
return {
isHh: Setting.isHh,
param: {
username: '',
password: ''
},
rules: {
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' }],
},
type: '0'
};
},
components: {
vFooter,
},
methods: {
...mapActions('user', [
'login'
]),
submitForm(form) {
this.$refs[form].validate(valid => {
if (valid) {
let data = {
account: this.type == '0' ? this.param.username : this.phoneParam.userphone,
password: this.type == '0' ? this.param.password : this.phoneParam.phonePassword,
source: this.type
}
this.login(data).then(() => {
let redirect = this.$route.query.redirect ? decodeURIComponent(this.$route.query.redirect) : '/index'
this.$router.replace(redirect)
}).catch(res => {})
} else {
return util.errorMsg('请输入账号和密码')
}
});
},
},
};
</script>
<style lang="scss" scoped>
.wrap{
position: relative;
width: 100%;
height: 100%;
background-image: url(../../../assets/img/login-bg.png);
background-size: 100%;
.header{
width: 100%;
height: 60px;
position: absolute;
top: 0;
left: 0;
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 18px;
.logo{
width: 150px;
margin-left: 20px;
&.hh{
width: 220px;
}
}
}
/deep/.main{
position: absolute;
left: 50%;
top: 42px;
transform: translate(-50%,0);
width: 1200px;
height: 82%;
margin-top: 60px;
background-image: url(../../../assets/img/login-input.png);
box-shadow:0px 0px 79px 0px rgba(11,15,65,0.36);
overflow: hidden;
.box {
width: 548px;
position: absolute;
left: 50%;
top: 50px;
transform: translate(-50%,0);
.el-tabs__nav-scroll{
display: flex;
justify-content: center;
}
.el-tabs__nav-wrap::after{
background-color: #fff;
opacity: 0;
.el-tabs__active-bar{
background-color: #000;
border-radius:2px;
}
.el-tabs__item{
padding: 0 90px;
color: #999;
&:hover{
color: #000;
}
&.is-active{
color: #333;
font-weight: bold;
}
}
}
.el-input__inner{
height: 80px;
line-height: 80px;
border:1px solid rgba(220,220,220,1);
border-radius:2px;
}
.btn {
width: 100%;
height: 88px;
margin-bottom: 50px;
font-weight: bold;
background:linear-gradient(90deg,rgba(94,206,253,1),rgba(91,67,231,1));
box-shadow:0px 7px 27px 0px rgba(50,129,255,0.51);
border-radius:10px;
}
}
}
.footer{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
}
</style>

@ -0,0 +1,299 @@
<template>
<div>
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-10">
<el-page-header @back="goBack" :content="experimentalName"></el-page-header>
</div>
<el-form label-width="100px">
<div class="flex-between">
<div></div>
<div>
<el-input placeholder="请输入学校/学生姓名" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</div>
</div>
</el-form>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div class="stat">
<div class="nums">
<div class="item">
<p class="name">实验总人数</p>
<p class="val">{{total}}</p>
</div>
<div class="item">
<p class="name">实验平均分</p>
<p class="val">{{avg}}</p>
</div>
</div>
<div class="chart" id="chart"></div>
</div>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-20">
<div></div>
<div>
<el-button type="primary" size="small" @click="delAllData">批量删除</el-button>
<el-button type="primary" size="small" @click="exportData">导出</el-button>
</div>
</div>
<el-table :data="listData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="reportId">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<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="schoolName" label="学校" align="center">
</el-table-column>
<el-table-column prop="experimentalName" label="考核名称" align="center">
<template slot-scope="scope">
{{experimentalName}}
</template>
</el-table-column>
<el-table-column v-if="className" prop="class" label="班级" align="center">
</el-table-column>
<el-table-column prop="userName" label="学生姓名" align="center"></el-table-column>
<el-table-column prop="workNumber" label="学号" align="center"></el-table-column>
<el-table-column prop="score" label="分数" align="center"></el-table-column>
<el-table-column prop="submitTime" label="提交时间" align="center">
</el-table-column>
<el-table-column label="操作" align="center" width="220">
<template slot-scope="scope">
<!-- <el-button type="text" @click="edit(scope.row)">修改分数</el-button> -->
<el-button type="text" @click="show(scope.row)">查看成绩报告</el-button>
<el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page">
</el-pagination>
</div>
</el-card>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import echarts from 'echarts'
export default {
data() {
return {
systemId: this.$route.query.systemId,
id: this.$route.query.id,
projectId: this.$route.query.projectId,
projectName: this.$route.query.name,
experimentalName: this.$route.query.experimentalName,
className: this.$route.query.class,
keyword: '',
listData: [],
multipleSelection: [],
page: 1,
pageSize: 10,
total: 0,
avg: 0,
};
},
mounted() {
this.getData()
},
methods: {
getData() {
let data = {
systemId: this.systemId,
page: this.page,
size: this.pageSize,
searchContant: this.keyword,
projectId: this.id
}
this.$get(this.api.queryEvaluationReport,data).then(res => {
let list = res.data.list
let score = 0
list.map(n => {
n.class = this.className
score += n.score
})
this.listData = list
this.total = res.data.totalCount
this.avg = score ? (score / res.data.totalCount).toFixed(2) : 0
this.getChart()
}).catch(res => {});
},
edit(row){
if(this.systemId == 2 || this.systemId == 3){
this.$router.push(`addexperiment?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else{
this.$router.push(`addexperiment?id=${row.reportId}`)
}
},
show(row){
if(this.systemId == 2){
this.$router.push(`showexperimentOption?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else if(this.systemId == 3){
this.$router.push(`showexperimentOptions?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else{
if(this.className){
this.$router.push(`show?id=${row.recordId}&projectId=${this.id}&reportId=${row.reportId}&studentId=${row.studentId}`)
}else{
this.$router.push(`show?id=${row.recordId}&type=1`)
}
}
},
exportData(){
if(!this.listData.length) return false
let selected = this.multipleSelection
let exportList = []
if(selected.length){
exportList = selected.map(item => {
return item.recordId
})
}else{
exportList = this.listData.map(item => {
return item.recordId
})
}
window.open(`${this.api.exportAchievement}?ids=${exportList.join(',')}&projectId=${this.projectId}&source=2`)
},
handleDelete(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteReport}?reportId=${row.reportId}&recordId=${row.recordId}`).then(res => {
this.$message.success('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return `reportId=${item.reportId}`
})
let delList1 = newArr.map(item => {
return `recordId=${item.recordId}`
})
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteReport}?${delList.join('&')}&${delList1.join('&')}`).then(res => {
this.$message.success('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {});
}else{
util.errorMsg('请先选择数据 !')
}
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleCurrentChange(val) {
this.page = val;
this.getData();
},
getChart(){
let data = [0,0,0,0,0,0,0,0,0,0]
let list = this.listData
list.map(n => {
n.score
if(n.score >= 0 && n.score <= 10){
data[0]++
}else if(n.score > 10 && n.score <= 20){
data[1]++
}else if(n.score > 20 && n.score <= 30){
data[2]++
}else if(n.score > 30 && n.score <= 40){
data[3]++
}else if(n.score > 40 && n.score <= 50){
data[4]++
}else if(n.score > 50 && n.score <= 60){
data[5]++
}else if(n.score > 60 && n.score <= 70){
data[6]++
}else if(n.score > 70 && n.score <= 80){
data[7]++
}else if(n.score > 80 && n.score <= 90){
data[8]++
}else if(n.score > 90 && n.score <= 100){
data[9]++
}
})
let myChart = echarts.init(document.getElementById('chart'))
myChart.setOption({
title: { text: '实验分数分布图' },
tooltip: {},
xAxis: {
name: '分数',
type: 'category',
boundaryGap: false,
data: ['0-10', '11-20', '21-30', '31-40', '41-50', '51-60', '61-70', '71-80','81-90','91-100']
},
yAxis: {
name: '人数',
type: 'value'
},
series: [{
data,
type: 'line',
areaStyle: {},
color: ['#8191fd']
}]
})
},
goBack() {
this.$router.back()
},
}
};
</script>
<style lang="scss" scoped>
/deep/.el-tabs__nav-wrap::after{
display: none;
}
.stat{
display: flex;
.nums {
display: flex;
align-items: center;
margin-right: 20px;
.item:nth-child(1) {
background-image: url('../../../assets/img/total.png');
}
.item:nth-child(2) {
background-image: url('../../../assets/img/avg.png');
}
.item {
width: 300px;
padding: 30px 30px;
margin: 0 10px;
box-sizing: border-box;
border-radius: 8px;
background-size: 100% 100%;
background-repeat: no-repeat;
p {
font-size: 18px;
color: #ffffff;
}
.val{
margin-top: 10px;
color: #ffffff;
font-size: 36px;
}
}
}
.chart{
flex: 1;
height: 300px;
}
}
</style>

@ -0,0 +1,368 @@
<template>
<div>
<el-row :gutter="20">
<el-col :span="24">
<el-card shadow="hover" class="mgb20">
<div class="flex-between">
<div class="per_title" @click="goback()">
<i class="el-icon-arrow-left"></i>
<span class="per_back">返回</span>
<span class="per_school">修改分数</span>
</div>
<div>
<el-button type="success" size="small" round class="mag" @click="saveAdd('form')">预览</el-button>
<el-button type="primary" size="small" round class="mag" @click="saveAdd('form')">发布成绩</el-button>
</div>
</div>
</el-card>
<el-card shadow="hover" class="mgb20">
<h6 style="text-align: center;font-size: 20px">实验成绩报告</h6>
<div class="flex-center mgb20 user_header">
<p class="addhr_tag"></p>
<span>基本信息</span>
</div>
<div>
<el-table :data="infoData" class="table" stripe header-align="center">
<el-table-column prop="projectName" label="实验名称" align="center">
</el-table-column>
<el-table-column prop="period" label="实验学时" align="center">
</el-table-column>
<el-table-column prop="userName" label="学生姓名" align="center">
</el-table-column>
<el-table-column prop="number" label="学生学号" align="center">
</el-table-column>
<el-table-column prop="class" label="学生班级" align="center">
</el-table-column>
<el-table-column prop="content" label="实验内容" align="center">
</el-table-column>
<el-table-column prop="desc" label="实验数据与结果分析" align="center">
</el-table-column>
<el-table-column prop="result" label="实验结论" align="center">
</el-table-column>
<el-table-column prop="experience" label="实验与心得体会" align="center">
</el-table-column>
<el-table-column prop="total" label="总分" align="center">
</el-table-column>
</el-table>
</div>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">实验项目名称</p>
</div>
<el-input v-model="form.projectName" type="textarea" :disabled="true" rows="5"></el-input>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">实验目的</p>
<span>得分50/60</span>
</div>
<el-input v-model="form.experimentGoal" type="textarea" :disabled="true" rows="5"></el-input>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">实验原理</p>
<span>得分50/60</span>
</div>
<el-input v-model="form.principle" type="textarea" :disabled="true" rows="5"></el-input>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">实验内容</p>
<span>得分50/60</span>
</div>
<el-input v-model="form.content" type="textarea" :disabled="true" rows="5"></el-input>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">实验步骤</p>
<span>得分50/60</span>
</div>
<el-input v-model="form.step" type="textarea" :disabled="true" rows="5"></el-input>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">实验数据</p>
<span>得分50/60</span>
</div>
<el-table :data="expData" class="table" stripe header-align="center">
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + 1}}
</template>
</el-table-column>
<el-table-column prop="module" label="模块" align="center">
</el-table-column>
<el-table-column prop="judgmentPointsName" label="考核点" align="center">
</el-table-column>
<el-table-column prop="userAnswer" label="学生答案" align="center">
</el-table-column>
<el-table-column prop="answer" label="参考答案" align="center">
</el-table-column>
<el-table-column prop="codeScore" label="得分" align="center">
</el-table-column>
</el-table>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">实验结论</p>
<span>得分50/60</span>
</div>
<el-input type="textarea" v-model="form.conclusion" rows="5"></el-input>
<div class="flex-between" style="margin-top: 10px">
<span>教师评分</span>
<div>
<el-input style="display: inline-block;width: auto;" placeholder="请输入"></el-input> (10)
</div>
</div>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">总结及心得体会</p>
<span>得分50/60</span>
</div>
<el-input type="textarea" v-model="form.summarize" rows="5"></el-input>
<div class="flex-between" style="margin-top: 10px">
<span>教师评分</span>
<div>
<el-input style="display: inline-block;width: auto;" placeholder="请输入"></el-input> (10)
</div>
</div>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="meta-title-wrap">
<p class="meta-title">对本实验过程及方法手段的改进建议</p>
<span>得分50/60</span>
</div>
<el-input type="textarea" rows="5" v-model="form.improvement"></el-input>
</el-card>
<el-card shadow="hover" class="mgb20">
<div class="flex-between mgb20">
<span>老师寄语</span>
</div>
<el-input type="textarea" rows="5"></el-input>
</el-card>
<el-card shadow="hover" class="mgb20">
<p class="mgb20">教师签名</p>
<div class="mgb20">
<el-radio v-model="autograph" label="1">不使用</el-radio>
<el-radio v-model="autograph" label="2">已有签名</el-radio>
<el-radio v-model="autograph" label="3">重新上传</el-radio>
</div>
<el-row v-if="autograph != 1">
<el-col :span="6">
<el-select class="sign-select" v-model="signId" placeholder="请选择签名" size="mini" v-show="autograph == 2">
<el-option
v-for="item in signList"
:key="item.id"
:label="item.signatureName"
:value="item.id"
>
</el-option>
</el-select>
<el-upload
:data="{userId: userId}"
:limit="1"
:action="api.uploadSignature"
list-type="picture-card"
:on-remove="handleRemove"
:on-exceed="handleExceed"
:on-success="uploadSuccess">
<i class="el-icon-plus"></i>
</el-upload>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data (){
return {
userId: this.$store.state.userLoginId,
id: this.$route.query.id,
infoData: [],
accountData: [],
analysisContent: '',
showData: '1',
autograph: '1',
form: {
projectName: '',
period: '',
userName: '',
content: '',
conclusion: '',
score: '',
},
pages: 1,
ipVisible: false,
configId : this.$store.state.configId,
keyword: '',
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}],
isEdit: false,
signList: [],
signId: ''
}
},
mounted(){
this.getData()
this.getSgin()
},
methods: {
getData(){
let data = {
// reportId: this.id
reportId: 97
}
this.$get(this.api.queryReport,data).then(res => {
this.form = res.data.report
this.form.score = res.data.record.score
let form = this.form
this.infoData.push({
projectName: form.projectName,
period: form.period,
userName: form.userName,
content: form.content,
conclusion: form.conclusion,
score: form.score,
analysis: form.analysis
})
}).catch(res => {});
},
getSgin(){
let data = {
userId: this.userId
}
this.$get(this.api.querySignature,data).then(res => {
this.signList = res.data
}).catch(res => {});
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
saveAdd(){
let data = {
systemId: this.configId,
systemName: this.form.systemName,
systemType: this.form.systemType,
systemAttribution: this.form.systemAttribution,
}
if(this.configId){
this.$post(this.api.updateServiceConfig,data).then((res) => {
util.successMsg('编辑成功');
this.$router.back()
}).catch((res) => {
})
}else{
this.$post(this.api.updateServiceConfig,data).then((res) => {
util.successMsg('添加成功');
this.$router.back()
}).catch((res) => {
})
}
},
SpanMethod({ row, column, rowIndex, columnIndex }) {
if (rowIndex % 2 === 0) {
if (columnIndex === 6) {
if(!row.Intranet){
return [1, 2];
}
}
// else if (columnIndex === 1) {
// return [0, 0];
// }
}
},
editMsg(){
this.isEdit = true
},
handleExceed(files, fileList) {
this.$message.warning(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res,file){
if(res.status == 200){
util.successMsg('上传成功')
this.getSgin()
}else{
util.errorMsg(res.errmessage)
}
},
goback() {
this.$confirm('确定返回?未更新的信息将不会保存。', '提示', {
type: 'warning'
})
.then(() => {
this.$router.back()
})
.catch(() => {});
}
}
}
</script>
<style lang="scss" scoped>
.meta-title{
margin-bottom: 10px;
font-size: 20px;
}
.step-title{
margin-bottom: 10px;
font-size: 16px;
color: #9278ff;
}
.border_lf{
border-left: 1px dashed #eee;
padding: 0 60px;
}
.border_lf label{
width: 120px;
}
.pad_none{
padding: 0 0 0 60px;
}
.edit-msg{
font-size: 16px;
cursor: pointer;
}
.sign-select{
/deep/.el-input{
width: 150px;
margin-bottom: 10px;
}
}
.meta-title-wrap{
display: flex;
justify-content: space-between;
}
.meta-title{
margin-bottom: 10px;
font-size: 14px;
}
.step-title{
margin-bottom: 10px;
font-size: 16px;
color: #9278ff;
}
.bd-title{
padding-top: 20px;
border-top: 1px dashed #ccc;
}
</style>

@ -0,0 +1,276 @@
<template>
<div class="page">
<h6 class="p-title">筛选</h6>
<div class="tool mul">
<ul class="filter">
<li>
<label>时间</label>
<el-radio-group size="small" v-model="month" @change="initData">
<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-radio-group size="small" v-model="projectPermissions" @change="initData">
<el-radio v-for="(item,index) in projectType" :key="index" :label="item.id" border>{{item.name}}</el-radio>
</el-radio-group>
</li>
<li>
<label>系统</label>
<el-select size="small" v-model="systemId" placeholder="请选择" @change="initData">
<el-option
v-for="item in systemList"
:key="item.value"
:label="item.label"
:value="item.id"
></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-button type="primary" size="small" @click="delAllData">批量删除</el-button>
</div>
</div>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true" :selectable="disabledSelection"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (page - 1) * pageSize + 1}}
</template>
</el-table-column>
<template v-if="projectPermissions == 1">
<el-table-column prop="experimentalClassName" label="班级" align="center"></el-table-column>
<el-table-column prop="experimentalName" label="实验名称" align="center"></el-table-column>
</template>
<el-table-column prop="projectName" label="项目名称" align="center">
</el-table-column>
<el-table-column prop="projectPermissions" label="分类" align="center">
<template slot-scope="scope">
{{scope.row.projectPermissions == 2 ? '竞赛' : projectType.find(n => n.id === scope.row.projectPermissions).name}}
</template>
</el-table-column>
<el-table-column prop="number" label="成绩报告数量" align="center"></el-table-column>
<el-table-column prop="creationTime" label="创建时间" align="center">
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="text" @click="entry(scope.row)" v-auth>成绩管理</el-button>
<el-button type="text" @click="handleDelete(scope.row)" :disabled="!scope.row.isdel">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page"></el-pagination>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import { Loading } from 'element-ui'
import util from '@/libs/util'
import Setting from '@/setting'
export default {
name: 'achievement',
data() {
return {
systemId: '',
systemList: Setting.systemList,
projectPermissions: this.$route.query.per ? Number(this.$route.query.per) : 0,
keyword: '',
startingtime: '',
endTime: '',
month: '',
listData: [],
multipleSelection: [],
dateList: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '近一个月'
},
{
id: 6,
name: '近六个月'
}
],
projectType: [
{
id: 0,
name: '练习'
},
{
id: 1,
name: '考核'
}
],
date: '',
page: 1,
pageSize: 10,
total: 0,
loadIns: null,
listDataAll: []
};
},
computed: {
...mapState('user', [
'userId'
]),
...mapState('project', [
'lastSystemId'
]),
},
watch: {
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.startingtime = val[0]
this.endTime = val[1]
}else{
this.startingtime = ''
this.endTime = ''
}
this.initData()
},
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted() {
this.systemId = this.lastSystemId ? this.lastSystemId : Setting.systemId
this.getData()
},
methods: {
...mapActions('project', [
'setSystemId'
]),
getData() {
this.loadIns = Loading.service({
background: 'rgba(255,255,255,.6)'
})
let data = {
searchContant: util.encodeStr(this.keyword),
startTime: this.startingtime,
endTime: this.endTime,
month: this.month,
page: this.page,
size: this.pageSize,
userId: this.userId
}
let url = this.api.queryAchievement
if(this.projectPermissions){
data.systemId = this.systemId
url = this.api.queryAchievementNew
}else{
data.systemId = this.systemId
data.projectPermissions = this.projectPermissions
}
this.$get(url,data).then(res => {
this.listData = res.data.list
this.total = res.data.total
this.$nextTick(() => {
this.loadIns.close()
})
}).catch(res => {
this.loadIns.close()
})
},
handlePage(){
let list = this.listDataAll
let result = []
list.map(n => {
if(!n.projectHiddenEntity) result.push(n)
})
this.listData = result.slice((this.page - 1) * this.pageSize,this.page * this.pageSize)
this.total = result.length
},
initData(){
this.$refs.table.clearSelection()
this.page = 1
this.getData()
},
disabledSelection(row,index){
if(row.isdel == 0) return false
return true
},
entry(row){
this.setSystemId(this.systemId)
if(this.projectPermissions){
this.$router.push(`teach?id=${row.id}&name=${row.experimentalName}&class=${row.experimentalClassName}&projectId=${row.projectId}&systemId=${this.systemId}`)
}else{
this.$router.push(`vir?id=${row.projectId}&name=${row.projectName}&class=${row.experimentalClassName}&systemId=${this.systemId}`)
}
},
handleDelete(row) {
this.$confirm('该项目下的所有成绩报告将会删除,是否继续?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteReportById}?projectIds=${row.projectId}&projectPermissions=${row.projectPermissions}&ids=${row.id ? row.id : ''}`).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {})
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return `projectIds=${item.projectId}`
})
let delList1 = newArr[0].id ? newArr.map(item => {
return `ids=${item.id}`
}) : []
this.$confirm('该项目下的所有成绩报告将会删除,是否继续?', '提示', {
type: 'warning'
})
.then(() => {
let data = `${delList.join('&')}&projectPermissions=${this.projectPermissions}&${delList1.length ? delList1.join('&') : ''}`
this.$post(`${this.api.deleteReportById}?${data}`).then(res => {
this.multipleSelection = [];
this.$refs.table.clearSelection()
util.successMsg('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {})
}else{
util.errorMsg('请先选择数据 !')
}
},
handleSelectionChange(val) {
this.multipleSelection = val
},
handleCurrentChange(val) {
this.page = val
this.getData()
},
}
};
</script>
<style lang="scss" scoped>
.el-radio.is-bordered+.el-radio.is-bordered{
margin-left: 0;
}
</style>

@ -0,0 +1,419 @@
<template>
<div class="box">
<el-row :gutter="24">
<el-col :span="24">
<el-card shadow="hover" class="m-b-20">
<div class="flex-between">
<el-page-header @back="goBack" content="查看报告"></el-page-header>
</div>
</el-card>
<div id="pdfDom">
<h6 style="text-align: center;font-size: 20px">标准实验报告</h6>
<div class="flex-center m-b-20 user_header">
<p class="addhr_tag"></p>
<span style="font-size: 18px">基本信息</span>
</div>
<div>
<el-table :data="infoData" class="info-table" stripe header-align="center">
<el-table-column prop="userName" label="学生姓名" align="center">
</el-table-column>
<el-table-column prop="workNumber" label="学生学号" align="center">
</el-table-column>
<el-table-column prop="experimentalClassName" label="学生班级" align="center">
</el-table-column>
<el-table-column prop="instructor" label="指导老师" align="center">
</el-table-column>
<el-table-column prop="period" label="实验学时" align="center">
</el-table-column>
<el-table-column prop="submitTime" label="实验时间" align="center">
</el-table-column>
<el-table-column prop="score" label="实验成绩" align="center">
</el-table-column>
</el-table>
</div>
<div class="m-b-20">
<div class="meta-title-wrap">
<p class="meta-title"><img src="@/assets/img/cup.png" alt=""> 实验项目名称</p>
</div>
<el-input v-model="form.proName" type="textarea" :disabled="true" rows="5"></el-input>
</div>
<div class="m-b-20">
<div class="meta-title-wrap">
<p class="meta-title">实验目的</p>
</div>
<!-- <el-input v-model="form.purpose" type="textarea" :disabled="true" rows="5"></el-input> -->
<div class="pre-wrap" v-html="form.purpose"></div>
</div>
<div class="m-b-20">
<div class="meta-title-wrap">
<p class="meta-title">实验数据</p>
</div>
<el-table :data="expData" class="table" stripe header-align="center">
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + 1}}
</template>
</el-table-column>
<el-table-column prop="judgmentPointsName" label="任务名称" align="center">
</el-table-column>
<el-table-column prop="userAnswer" label="学生答案" align="center">
<template slot-scope="scope">
<pre v-html="scope.row.userAnswer" style="white-space: pre-wrap"></pre>
</template>
</el-table-column>
<el-table-column prop="answer" label="参考答案" align="center">
<template slot-scope="scope">
<pre v-html="scope.row.answer" style="white-space: pre-wrap"></pre>
</template>
</el-table-column>
<el-table-column prop="codeScore" label="得分" align="center">
</el-table-column>
</el-table>
</div>
<div class="m-b-20">
<div class="meta-title-wrap">
<p class="meta-title">实验总结与体会</p>
</div>
<el-input type="textarea" v-model="form.summarize" rows="5" disabled></el-input>
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import util from '@/libs/util'
import Setting from '@/setting'
export default {
data (){
return {
title: '实验报告',
form: {
analysis: '',
conclusion: '',
content: ``,
data: '',
purpose: ``,
experimentId: '',
experimentalClassName: '',
improvement: '',
laboratory: '',
period: '',
principle: '',
proName: '',
score: 0,
step: ``,
submitTime: '',
summarize: '',
instructor: '',
userId: this.userId,
userName: '',
workNumber: '',
},
type: this.$route.query.type,
id: this.$route.query.id,
recordId: this.$route.query.recordId,
reportId: this.$route.query.reportId,
projectId: this.$route.query.projectId,
studentId: this.$route.query.studentId,
infoData: [],
expData: [],
accountData: [],
showData: '1',
autograph: '1',
pages: 1,
ipVisible: false,
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}],
conclusionOptions: [
{
value: 1,
label: '结论符合预期'
}
],
}
},
computed: {
...mapState('user', [
'userId'
]),
},
mounted(){
this.getData()
},
methods: {
getData(){
if(this.type){
let data = {
recordId: this.id,
}
this.$get(this.api.queryVirtualReport,data).then(res => {
this.form = res.data.report
let expData = res.data.data
let form = this.form
let score = form.score
if(expData){
if(score){
expData.map(n => {
if(n.isError){
score -= n.codeScore
n.codeScore = 0
}
})
form.score = score
}
this.expData = expData
}
this.infoData.push({
workNumber: form.workNumber,
experimentalClassName: form.experimentalClassName,
instructor: form.instructor,
period: form.period,
laboratory: form.laboratory,
submitTime: form.submitTime,
score: form.score,
userName: form.userName
})
}).catch(res => {});
}else{
let data = {
studentId: this.studentId,
projectId: this.projectId,
recordId: this.id,
reportId: this.reportId
}
this.$get(this.api.queryArchievement,data).then(res => {
this.form = res.data.report ? res.data.report : {}
let expData = res.data.data
let form = this.form
let score = form.score
if(expData){
if(score){
expData.map(n => {
if(n.isError){
score -= n.codeScore
n.codeScore = 0
}
})
form.score = score
}
this.expData = expData
}
this.infoData.push({
workNumber: form.workNumber,
experimentalClassName: form.experimentalClassName,
instructor: form.instructor,
period: form.period,
laboratory: form.laboratory,
submitTime: form.submitTime,
score: form.score,
userName: form.userName
})
}).catch(res => {});
}
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
saveAdd(){
let data = {
systemId: this.configId,
systemName: this.form.systemName,
systemType: this.form.systemType,
systemAttribution: this.form.systemAttribution,
}
if(this.configId){
this.$post(this.api.updateServiceConfig,data).then((res) => {
util.successMsg('编辑成功');
this.goBack()
}).catch((res) => {
})
}else{
this.$post(this.api.updateServiceConfig,data).then((res) => {
util.successMsg('添加成功');
this.goBack()
}).catch((res) => {
})
}
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
SpanMethod({ row, column, rowIndex, columnIndex }) {
if (rowIndex % 2 === 0) {
if (columnIndex === 6) {
if(!row.Intranet){
return [1, 2];
}
}
// else if (columnIndex === 1) {
// return [0, 0];
// }
}
},
goBack(){
this.$router.go(-1)
},
exportPage(){
var title = this.title;
html2Canvas(document.querySelector('#pdfDom'), {
allowTaint: true
}).then(function (canvas) {
let contentWidth = canvas.width
let contentHeight = canvas.height
let pageHeight = contentWidth / 592.28 * 841.89
let leftHeight = contentHeight
let position = 0
let imgWidth = 595.28
let imgHeight = 592.28 / contentWidth * contentHeight
let pageData = canvas.toDataURL('image/jpeg', 1.0)
let PDF = new JsPDF('', 'pt', 'a4')
if (leftHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
} else {
while (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
if (leftHeight > 0) {
PDF.addPage()
}
}
}
PDF.save(title + '.pdf')
}
)
}
}
}
</script>
<style lang="scss" scoped>
.box{
padding: 0 50px;
background-color: #fff;
}
/deep/.el-textarea.is-disabled .el-textarea__inner{
color: #777;
background-color: #e5dfff;
}
.pre-wrap{
min-height: 117px;
padding: 5px 15px;
color: #777;
background-color: #e5dfff;
}
#pdfDom{
padding: 50px;
/deep/.info-table{
margin-bottom: 40px;
border: 0;
th{
background-color: #fff !important;
.cell{
color: #444;
}
}
tr{
border: 0;
}
tr:hover,tr:hover>td{
background-color: #e5dfff !important;
}
td{
border: {
left: 4px solid #fff;
right: 4px solid #fff;
}
&:first-child{
border-left: 0;
}
&:last-child{
border-right: 0;
}
background-color: #e5dfff;
border-bottom: 0;
}
}
/deep/.table th{
background-color: #e1eaff !important;
.cell{
color: #555555;
}
}
}
/deep/.cell{
font-size: 12px;
}
/deep/.el-row{
padding-top: 20px;
margin: 0 !important;
}
.form-item{
display: flex;
align-items: center;
}
.form-item .el-input{
width: auto;
}
.form-item span{
margin-right: 10px;
}
.meta-title-wrap{
display: flex;
justify-content: space-between;
align-items: center;
span{
font-size: 13px;
color: #444;
}
}
.flex-between{
span{
font-size: 13px;
color: #444;
}
}
.meta-title{
display: flex;
align-items: center;
padding: 10px 20px;
margin-bottom: 10px;
font-size: 16px;
color: #fff;
background-color: #9278ff;
img{
width: 20px;
margin-right: 10px;
}
}
.step-title{
margin-bottom: 10px;
font-size: 16px;
color: #9278ff;
}
.bd-title{
padding-top: 20px;
border-top: 1px dashed #ccc;
}
</style>

@ -0,0 +1,304 @@
<template>
<div>
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-10">
<el-page-header @back="goBack" :content="experimentalName"></el-page-header>
</div>
<el-form label-width="100px">
<div class="flex-between">
<div></div>
<div>
<el-input size="small" placeholder="请输入学校/学生姓名" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</div>
</div>
</el-form>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div class="stat">
<div class="nums">
<div class="item">
<p class="name">实验总人数</p>
<p class="val">{{total}}</p>
</div>
<div class="item">
<p class="name">实验平均分</p>
<p class="val">{{avg}}</p>
</div>
</div>
<div class="chart" id="chart"></div>
</div>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-20">
<div>
</div>
<div>
<el-button type="primary" size="small" @click="delAllData">批量删除</el-button>
<el-button type="primary" size="small" @click="exportData">导出</el-button>
</div>
</div>
<el-table :data="listData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="reportId">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<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="schoolName" label="学校" align="center">
</el-table-column>
<el-table-column prop="experimentalName" label="考核名称" align="center">
<template slot-scope="scope">
{{experimentalName}}
</template>
</el-table-column>
<el-table-column v-if="className" prop="class" label="班级" align="center">
</el-table-column>
<el-table-column prop="userName" label="学生姓名" align="center"></el-table-column>
<el-table-column prop="workNumber" label="学号" align="center"></el-table-column>
<el-table-column prop="score" label="分数" align="center"></el-table-column>
<el-table-column prop="submitTime" label="提交时间" align="center">
</el-table-column>
<el-table-column label="操作" align="center" width="220">
<template slot-scope="scope">
<!-- <el-button type="text" @click="edit(scope.row)">修改分数</el-button> -->
<el-button type="text" @click="show(scope.row)">查看成绩报告</el-button>
<el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page">
</el-pagination>
</div>
</el-card>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import echarts from 'echarts'
export default {
data() {
return {
systemId: this.$route.query.systemId,
id: this.$route.query.id,
experimentalName: this.$route.query.name,
className: this.$route.query.class,
projectId: this.$route.query.projectId,
keyword: '',
listDataAll: [],
listData: [],
multipleSelection: [],
page: 1,
pageSize: 10,
total: 0,
avg: 0,
};
},
mounted() {
this.getData()
},
methods: {
getData() {
let data = {
id: this.id
}
this.$get(this.api.getTeachAchievement,data).then(res => {
let list = res.data
let score = 0
list.map(n => {
n.class = this.className
score += n.score
})
this.listDataAll = list
this.handlePage()
this.total = list.length
this.avg = score ? (score / list.length).toFixed(2) : 0
this.getChart()
}).catch(res => {});
},
handlePage(){
let list = this.listDataAll
this.listData = list.slice((this.page - 1) * this.pageSize,this.page * this.pageSize)
this.total = list.length
},
edit(row){
if(this.systemId == 2 || this.systemId == 3){
this.$router.push(`addexperiment?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else{
this.$router.push(`addexperiment?id=${row.reportId}`)
}
},
show(row){
if(this.systemId == 2){
this.$router.push(`showexperimentOption?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else if(this.systemId == 3){
this.$router.push(`showexperimentOptions?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else{
if(this.className){
this.$router.push(`show?id=${row.recordId}&projectId=${row.projectId}&reportId=${row.reportId}&studentId=${row.studentId}`)
}else{
this.$router.push(`show?id=${row.recordId}&type=1`)
}
}
},
exportData(){
if(!this.listData.length) return false
let selected = this.multipleSelection
let exportList = []
if(selected.length){
exportList = selected.map(item => {
return item.recordId
})
}else{
exportList = this.listData.map(item => {
return item.recordId
})
}
console.log(exportList.join(','),this.id,this.projectId)
window.open(`${this.api.exportAchievement}?ids=${exportList.join(',')}&projectId=${this.projectId}&source=2`)
},
handleDelete(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteReport}?reportId=${row.reportId}&recordId=${row.recordId}`).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return `reportId=${item.reportId}`
})
let delList1 = newArr.map(item => {
return `recordId=${item.recordId}`
})
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteReport}?${delList.join('&')}&${delList1.join('&')}`).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {});
}else{
util.errorMsg('请先选择数据 !')
}
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleCurrentChange(val) {
this.page = val;
this.handlePage();
},
getChart(){
let data = [0,0,0,0,0,0,0,0,0,0]
let list = this.listData
list.map(n => {
n.score
if(n.score >= 0 && n.score <= 10){
data[0]++
}else if(n.score > 10 && n.score <= 20){
data[1]++
}else if(n.score > 20 && n.score <= 30){
data[2]++
}else if(n.score > 30 && n.score <= 40){
data[3]++
}else if(n.score > 40 && n.score <= 50){
data[4]++
}else if(n.score > 50 && n.score <= 60){
data[5]++
}else if(n.score > 60 && n.score <= 70){
data[6]++
}else if(n.score > 70 && n.score <= 80){
data[7]++
}else if(n.score > 80 && n.score <= 90){
data[8]++
}else if(n.score > 90 && n.score <= 100){
data[9]++
}
})
let myChart = echarts.init(document.getElementById('chart'))
myChart.setOption({
title: { text: '实验分数分布图' },
tooltip: {},
xAxis: {
name: '分数',
type: 'category',
boundaryGap: false,
data: ['0-10', '11-20', '21-30', '31-40', '41-50', '51-60', '61-70', '71-80','81-90','91-100']
},
yAxis: {
name: '人数',
type: 'value'
},
series: [{
data,
type: 'line',
areaStyle: {},
color: ['#8191fd']
}]
})
},
goBack() {
this.$router.push('list?per=1')
},
}
};
</script>
<style lang="scss" scoped>
/deep/.el-tabs__nav-wrap::after{
display: none;
}
.stat{
display: flex;
.nums {
display: flex;
align-items: center;
margin-right: 20px;
.item:nth-child(1) {
background-image: url('../../../assets/img/total.png');
}
.item:nth-child(2) {
background-image: url('../../../assets/img/avg.png');
}
.item {
width: 300px;
padding: 30px 30px;
margin: 0 10px;
box-sizing: border-box;
border-radius: 8px;
background-size: 100% 100%;
background-repeat: no-repeat;
p {
font-size: 18px;
color: #ffffff;
}
.val{
margin-top: 10px;
color: #ffffff;
font-size: 36px;
}
}
}
.chart{
flex: 1;
height: 300px;
}
}
</style>

@ -0,0 +1,297 @@
<template>
<div>
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-10">
<el-page-header @back="goBack" :content="experimentName"></el-page-header>
</div>
<el-form label-width="100px">
<div class="flex-between">
<div></div>
<div>
<el-input size="small" placeholder="请输入学校/学生姓名" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</div>
</div>
</el-form>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div class="stat">
<div class="nums">
<div class="item">
<p class="name">实验总人数</p>
<p class="val">{{total}}</p>
</div>
<div class="item">
<p class="name">实验平均分</p>
<p class="val">{{avg}}</p>
</div>
</div>
<div class="chart" id="chart"></div>
</div>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-20">
<div>
</div>
<div>
<el-button type="primary" size="small" @click="delAllData">批量删除</el-button>
<el-button type="primary" size="small" @click="exportData">导出</el-button>
</div>
</div>
<el-table :data="listData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="reportId">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<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="schoolName" label="学校" align="center">
</el-table-column>
<el-table-column v-if="className" prop="class" label="班级" align="center">
</el-table-column>
<el-table-column prop="userName" label="学生姓名" align="center"></el-table-column>
<el-table-column prop="workNumber" label="学号" align="center"></el-table-column>
<el-table-column prop="score" label="分数" align="center"></el-table-column>
<el-table-column prop="submitTime" label="提交时间" align="center">
</el-table-column>
<el-table-column label="操作" align="center" width="220">
<template slot-scope="scope">
<!-- <el-button type="text" @click="edit(scope.row)">修改分数</el-button> -->
<el-button type="text" @click="show(scope.row)">查看成绩报告</el-button>
<el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page">
</el-pagination>
</div>
</el-card>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import echarts from 'echarts'
export default {
data() {
return {
systemId: this.$route.query.systemId,
projectId: this.$route.query.id,
experimentName: this.$route.query.name,
className: this.$route.query.class,
keyword: '',
listDataAll: [],
listData: [],
multipleSelection: [],
page: 1,
pageSize: 10,
total: 0,
avg: 0,
};
},
mounted() {
this.getData()
},
methods: {
getData() {
let data = {
projectId: this.projectId
}
this.$get(this.api.getImitationAchievement,data).then(res => {
let list = res.data
let score = 0
list.map(n => {
n.class = this.className
score += n.score
})
this.listDataAll = list
this.handlePage()
this.total = list.length
this.avg = score ? (score / list.length).toFixed(2) : 0
this.getChart()
}).catch(res => {});
},
handlePage(){
let list = this.listDataAll
this.listData = list.slice((this.page - 1) * this.pageSize,this.page * this.pageSize)
this.total = list.length
},
edit(row){
if(this.systemId == 2 || this.systemId == 3){
this.$router.push(`addexperiment?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else{
this.$router.push(`addexperiment?id=${row.reportId}`)
}
},
show(row){
if(this.systemId == 2){
this.$router.push(`showexperimentOption?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else if(this.systemId == 3){
this.$router.push(`showexperimentOptions?id=${row.reportId}&stuId=${row.userId}&studentName=${row.studentName}&class=${row.class}`)
}else{
if(this.class){
this.$router.push(`show?id=${row.recordId}&projectId=${this.projectId}&reportId=${row.reportId}`)
}else{
this.$router.push(`show?id=${row.recordId}&type=1`)
}
}
},
exportData(){
if(!this.listData.length) return false
let selected = this.multipleSelection
let exportList = []
if(selected.length){
exportList = selected.map(item => {
return item.recordId
})
}else{
exportList = this.listData.map(item => {
return item.recordId
})
}
window.open(`${this.api.exportAchievement}?ids=${exportList.join(',')}&projectId=${this.projectId}&source=1`)
},
handleDelete(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteReport}?reportId=${row.reportId}&recordId=${row.recordId}`).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {});
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return `reportId=${item.reportId}`
})
let delList1 = newArr.map(item => {
return `recordId=${item.recordId}`
})
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteReport}?${delList.join('&')}&${delList1.join('&')}`).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {});
}else{
util.errorMsg('请先选择数据 !');
}
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleCurrentChange(val) {
this.page = val;
this.handlePage();
},
getChart(){
let data = [0,0,0,0,0,0,0,0,0,0]
let list = this.listData
list.map(n => {
n.score
if(n.score >= 0 && n.score <= 10){
data[0]++
}else if(n.score > 10 && n.score <= 20){
data[1]++
}else if(n.score > 20 && n.score <= 30){
data[2]++
}else if(n.score > 30 && n.score <= 40){
data[3]++
}else if(n.score > 40 && n.score <= 50){
data[4]++
}else if(n.score > 50 && n.score <= 60){
data[5]++
}else if(n.score > 60 && n.score <= 70){
data[6]++
}else if(n.score > 70 && n.score <= 80){
data[7]++
}else if(n.score > 80 && n.score <= 90){
data[8]++
}else if(n.score > 90 && n.score <= 100){
data[9]++
}
})
let myChart = echarts.init(document.getElementById('chart'))
myChart.setOption({
title: { text: '实验分数分布图' },
tooltip: {},
xAxis: {
name: '分数',
type: 'category',
boundaryGap: false,
data: ['0-10', '11-20', '21-30', '31-40', '41-50', '51-60', '61-70', '71-80','81-90','91-100']
},
yAxis: {
name: '人数',
type: 'value'
},
series: [{
data,
type: 'line',
areaStyle: {},
color: ['#8191fd']
}]
})
},
goBack() {
this.$router.back()
},
}
};
</script>
<style lang="scss" scoped>
/deep/.el-tabs__nav-wrap::after{
display: none;
}
.stat{
display: flex;
.nums {
display: flex;
align-items: center;
margin-right: 20px;
.item:nth-child(1) {
background-image: url('../../../assets/img/total.png');
}
.item:nth-child(2) {
background-image: url('../../../assets/img/avg.png');
}
.item {
width: 300px;
padding: 30px 30px;
margin: 0 10px;
box-sizing: border-box;
border-radius: 8px;
background-size: 100% 100%;
background-repeat: no-repeat;
p {
font-size: 18px;
color: #ffffff;
}
.val{
margin-top: 10px;
color: #ffffff;
font-size: 36px;
}
}
}
.chart{
flex: 1;
height: 300px;
}
}
</style>

@ -0,0 +1,492 @@
<template>
<div>
<el-form :disabled="isDetail">
<el-card shadow="hover" class="m-b-20">
<div class="flex-between">
<el-page-header @back="goBack" :content="isDetail ? '查看' : (id ? '更新' : '创建') + '教学实验'"></el-page-header>
<div>
<el-button type="primary" size="small" @click="upload" v-show="!isDetail">{{id ? '更新' : '创建'}}</el-button>
</div>
</div>
</el-card>
<el-card shadow="hover" class="mgr20 m-b-20">
<div>
<p class="m-b-20">考核名称</p>
<el-input
placeholder="请输入考核名称"
v-model="experimentalName"
clearable
maxlength="15"
class="inline-input"
@change="judgeExpName"
></el-input>
</div>
</el-card>
<el-card shadow="hover" class="mgr20 m-b-20">
<div>
<p class="m-b-20">班级名称</p>
<el-input
placeholder="请输入班级名称"
v-model="experimentalClassName"
clearable
maxlength="15"
class="inline-input"
></el-input>
</div>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div>
<p class="m-b-20">发布方式</p>
<el-radio :disabled="id ? true : false" v-model="type" label="1" class="fons">手动发布</el-radio>
<el-radio :disabled="id ? true : false" v-model="type" label="2" class="fons">定时发布</el-radio>
</div>
</el-card>
<!-- 根据发布方式判断时间的显示 -->
<el-card shadow="hover" class="m-b-20">
<div>
<p class="m-b-20">实验时间</p>
<!-- 手动发布显示 -->
<div class="date-inputs" v-if="type==1">
实验时长
<el-input size="small" v-model="duration.day" placeholder></el-input>
<el-input size="small" v-model="duration.hour" placeholder></el-input>
<el-input size="small" v-model="duration.minute" placeholder></el-input>
</div>
<!-- 定时发布显示 -->
<div v-if="type==2" class="addAssess">
<span class="mgr10">开始时间:</span>
<el-date-picker
size="small"
v-model="date"
type="datetimerange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
></el-date-picker>
</div>
</div>
</el-card>
<el-card shadow="hover" class="mgr20 m-b-20">
<div>
<p class="m-b-20">系统</p>
<div class="inline-input">
<el-select v-model="systemId" placeholder="请选择" @change="initData">
<el-option
v-for="item in systemList"
:key="item.value"
:label="item.label"
:value="item.id"
></el-option>
</el-select>
</div>
</div>
</el-card>
<!-- 实训项目模块 -->
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-20">
<span>实训项目</span>
<div style="display: inline-flex;">
<div>
<el-input size="small" placeholder="请输入项目名称" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</div>
<el-button style="margin-left: 5px" type="primary" size="small" round @click="toProject">自定义实验项目</el-button>
</div>
</div>
<!-- 实训项目表格 -->
<el-table :data="projectData" class="table" stripe header-align="center">
<!-- 单选实训项目ID -->
<el-table-column width="60" label="选择" align="center">
<template slot-scope="scope">
<el-radio v-model="projectId" :label="scope.row.projectId">&nbsp;</el-radio>
</template>
</el-table-column>
<el-table-column prop="projectName" label="项目名称" align="center"></el-table-column>
<el-table-column prop="auth" label="项目权限" align="center">
<template slot-scope="scope">
{{projectPermissionsList[scope.row.projectPermissions]}}
</template>
</el-table-column>
<el-table-column prop="creater" label="创建人" align="center">
<template slot-scope="scope">
{{roleStatus(scope.row.founder)}}
</template>
</el-table-column>
<el-table-column prop="creationTime" label="创建时间" align="center"></el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="text" @click="showProject(scope.row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
background
:page-size="pageSize"
@current-change="handleCurrentChange"
layout="total,prev, pager, next"
:total="total"
></el-pagination>
</div>
</el-card>
<!-- 邀请码 -->
<el-card shadow="hover">
<div style="margin-bottom: 10px">
<p class="m-b-20">设置邀请码</p>
<el-radio v-model="isCode" label="0"></el-radio>
<el-radio v-model="isCode" label="1"></el-radio>
</div>
<div v-show="isCode == 0">
<el-input style="display: inline-block;width: auto;margin-right: 10px" v-model.number="invitationCode" maxlength="6" placeholder="请设置6个数字"></el-input>
<el-button type="text" @click="createInv">随机</el-button>
</div>
</el-card>
</el-form>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
id: '',
roleStatus: util.getRoleName,
systemId: Setting.systemId,
systemList: Setting.systemList,
isDetail: true,
duration: {
day: '',
hour: '',
minute: ''
},
keyword: '',
searchTimer: null,
date: '',
experimentDuration: '0d0h0m',
experimentalNumber: 0,
projectId: '',
projectName: '',
status: '',
surplusTime: '',
experimentalName: '',//
experimentalClassName: '', //
type: '1',
isCode: '0', //
startTime: '0000-00-00 00:00:00', //
stopTime: '0000-00-00 00:00:00', //
invitationCode: '',
currPage: 1,
projectDataAll: [],
projectData: [],
invRepeat: false,
pickerOptions: {
disabledDate: time => {
return time.getTime() < new Date().getTime() - 86400000
}
},
projectPermissionsList: ['练习','考核','竞赛'],
projectQueryData: {
userId: this.userId,
systemId: this.systemId
},
page: 1,
pageSize: 5,
total: 0,
multipleSelection: [],
isToProject: false,
expNameRepeat: false
};
},
computed: {
...mapState('user', [
'userId'
]),
...mapState('project', [
'assFields'
]),
},
mounted() {
console.log(22,this.assFields)
this.date = [util.formatDate("yyyy-MM-dd hh:mm:ss",new Date(new Date().getTime() + 300000)),util.formatDate("yyyy-MM-dd hh:mm:ss",new Date(new Date().getTime() + 300000))]
this.id = this.$route.query.id
this.isDetail = Boolean(this.$route.query.show)
this.id && this.getData()
this.getProjectData()
this.recoveryData()
},
beforeDestroy(){
if(!this.isToProject) this.setAss({})
},
watch: {
date: function(val){
if(val[0] != '0000-00-00 00:00:00'){
this.startTime = util.formatDate("yyyy-MM-dd hh:mm:ss",new Date(val[0]))
this.stopTime = util.formatDate("yyyy-MM-dd hh:mm:ss",new Date(val[1]))
}
},
duration: {
handler(n,o){
this.experimentDuration = `${n.day ? n.day : 0}d${n.hour ? n.hour : 0}h${n.minute ? n.minute : 0}m`
},
deep: true
},
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
methods: {
...mapActions('project', [
'setAss'
]),
getProjectData(){
let data = {
pageNo: this.page,
pageSize: 10000,
userId: this.userId,
systemId: this.systemId,
projectName: this.keyword,
projectPermissions: 1,
}
this.$get(this.api.queryAllManagements,data).then(res => {
let list = res.pageInfo.list
let result = []
list.map(n => {
n.enable || result.push(n)
})
this.projectDataAll = result
this.total = result.length
this.handlePage()
}).catch(res => {});
},
handlePage(){
let list = this.projectDataAll
let result = list.slice((this.page - 1) * this.pageSize,this.page * this.pageSize)
this.projectData = result
},
initData(){
this.page = 1
this.getProjectData()
},
recoveryData(){
if(JSON.stringify(this.assFields) != '{}'){
let info = this.assFields
this.experimentDuration = info.experimentDuration
this.experimentalClassName = info.experimentalClassName
this.experimentalName = info.experimentalName
this.invitationCode = info.invitationCode
this.isCode = String(info.isCode)
this.projectId = info.projectId
this.startTime = info.startTime
this.stopTime = info.stopTime
this.surplusTime = info.surplusTime
this.type = String(info.type)
this.expNameRepeat = info.expNameRepeat
this.formatDuration()
}
},
upload() {
if(!this.experimentalName) return this.$message.warning('请填写考核名称')
if(this.expNameRepeat) return this.$message.warning('考核名称重复,请重新输入')
if(!this.experimentalClassName) return this.$message.warning('请填写班级名称')
if(this.type == 1){
this.status = 1
}else{
if(new Date().getTime() > new Date(this.startTime).getTime()) return this.$message.warning('开始时间不能早于当前时间')
this.status = 1
let timestamp = new Date(new Date(this.stopTime).getTime() - new Date(this.startTime).getTime())
let minute = 1000 * 60
let hour = minute * 60
let day = hour * 24
this.experimentDuration = `${Math.floor(timestamp / day)}d${Math.floor(timestamp % day / hour)}h${Math.floor(timestamp % day % hour / minute)}m`
}
if(this.type == 1 && this.experimentDuration == '0d0h0m') return this.$message.warning('请填写实验时长')
if(this.type == 2 && this.startTime == '0000-00-00 00:00:00') return this.$message.warning('请填写实验时间')
if(!this.projectId) return this.$message.warning('请选择实训项目')
this.projectName = this.projectData.find(n => n.projectId == this.projectId).projectName
if(this.isCode == 0){
if(!this.invitationCode) return this.$message.warning('请设置邀请码')
if(!this.invitationCode || String(this.invitationCode).length < 6 || isNaN(this.invitationCode)) return this.$message.warning('请输入6位纯数字邀请码')
// if(this.invRepeat) return this.$message.warning('')
}
let data = {
id: this.id,
experimentDuration: this.experimentDuration,
creationTime: this.id ? this.creationTime : util.formatDate("yyyy-MM-dd hh:mm:ss"),
experimentalClassName: this.experimentalClassName,
experimentalName: this.experimentalName,
experimentalNumber: this.experimentalNumber,
invitationCode: this.invitationCode,
isCode: this.isCode,
projectId: this.projectId,
projectName: this.projectName,
status: Number(this.status),
surplusTime: this.surplusTime,
type: Number(this.type),
userId: this.userId,
systemId: this.systemId
}
if(this.type == 2){
data.startTime = this.startTime
data.stopTime = this.stopTime
}else{
data.startTime = '0000-00-00 00:00:00'
data.stopTime = '0000-00-00 00:00:00'
}
if(this.id){
this.$post(this.api.expUpdate, data).then(res => {
util.successMsg('修改成功');
this.$router.back()
})
.catch(err => {
});
}else{
this.$post(this.api.expSave, data).then(res => {
util.successMsg('创建成功');
this.$router.back()
})
.catch(err => {
});
}
},
getData() {
this.$get(this.api.expInfo + this.id)
.then(res => {
if(res.errmessage == 'success'){
let info = res.ExperimentalTeaching
this.creationTime = info.creationTime
this.experimentDuration = info.experimentDuration
this.experimentalClassName = info.experimentalClassName
this.experimentalName = info.experimentalName
this.experimentalNumber = info.experimentalNumber
this.invitationCode = info.invitationCode
this.isCode = String(info.isCode)
this.projectId = info.projectId
this.projectName = info.projectName
this.startTime = info.startTime
this.status = info.status
this.stopTime = info.stopTime
this.surplusTime = info.surplusTime
this.type = String(info.type)
this.formatDuration()
}else{
util.errorMsg('查询失败');
}
})
.catch(err => {
});
},
formatDuration(){
let duration = this.experimentDuration.replace(/\D+/g,',').split(',')
this.duration = {
day: duration[0],
hour: duration[1],
minute: duration[2]
}
this.date = [this.startTime,this.stopTime]
},
handleCacheData(){
let data = {
id: this.id,
experimentDuration: this.experimentDuration,
experimentalClassName: this.experimentalClassName,
experimentalName: this.experimentalName,
invitationCode: this.invitationCode,
isCode: this.isCode,
projectId: this.projectId,
startTime: this.startTime,
stopTime: this.stopTime,
surplusTime: this.surplusTime,
type: this.type,
expNameRepeat: this.expNameRepeat
}
this.setAss(data)
this.isToProject = true
},
toProject(){
this.handleCacheData()
this.$router.push('/project')
},
showProject(row){
this.handleCacheData()
this.$router.push(`/addproject?id=${row.projectId}&show=1`)
},
goBack() {
if(this.isDetail){
this.$router.back()
}else{
this.$confirm('确定返回?未更新的信息将不会保存。', '提示', {
type: 'warning'
})
.then(() => {
this.$router.back()
})
.catch(() => {});
}
},
varifyInv() {
this.$get(this.api.getInvitationCode, { invitationCode: this.invitationCode })
.then(res => {
if(res.InvitationCode) {
this.$message.warning('邀请码重复,请重新输入')
this.invRepeat = true
}else{
this.invRepeat = false
}
})
.catch(err => {});
},
createInv() {
let result = ''
for(let i=0; i<6; i++){
result += Math.floor(Math.random()*10)
}
this.invitationCode = result
// this.varifyInv()
},
handleCurrentChange(val){
this.page = val
this.handlePage()
},
judgeExpName(){
this.$get(this.api.expCheck, { experimentalName: util.encodeStr(this.experimentalName) })
.then(res => {
if(res.errmessage != 'success') {
this.$message.warning('考核名称重复,请重新输入')
this.expNameRepeat = true
}else{
this.expNameRepeat = false
}
})
.catch(err => {});
},
},
};
</script>
<style lang="scss" scoped>
.inline-input{
width: 300px;
}
.date-inputs{
.el-input{
width: 100px;
}
}
</style>

@ -0,0 +1,389 @@
<template>
<div class="page">
<h6 class="p-title">筛选</h6>
<div class="tool mul">
<ul class="filter">
<li>
<label>实验时间</label>
<el-radio-group size="small" v-model="form.month" @change="initData">
<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" style="margin-left: 10px;" 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.type" clearable placeholder="请选择发布类型" @change="initData">
<el-option v-for="(item,index) in typeList" :key="index" :label="item.name" :value="item.value"></el-option>
</el-select>
</li>
<li>
<label>实验状态</label>
<el-select size="small" v-model="form.status" clearable placeholder="请选择实验状态" @change="initData">
<el-option v-for="(item,index) in statusList" :key="index" :label="item.name" :value="item.value"></el-option>
</el-select>
</li>
<li>
<label>系统</label>
<el-select size="small" v-model="systemId" placeholder="请选择" @change="initData">
<el-option label="不限" value=""></el-option>
<el-option
v-for="item in systemList"
:key="item.value"
:label="item.label"
:value="item.id"
></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-button type="primary" size="small" round @click="add" v-auth>创建实验</el-button>
<el-button type="primary" size="small" round @click="delAllData" v-auth>批量删除</el-button>
</div>
</div>
<el-table ref="table" :data="listData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" :selectable="row => row.status!=2" width="50" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (page - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="experimentalClassName" label="实验班级" align="center">
</el-table-column>
<el-table-column prop="experimentalName" label="考核名称" min-width="120" align="center">
</el-table-column>
<el-table-column prop="projectName" 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 label="邀请码" align="center">
<template slot-scope="scope">
<span>{{scope.row.isCode == 0 ? scope.row.invitationCode : ''}}</span>
</template>
</el-table-column>
<el-table-column prop="adminName" label="发布类型" align="center">
<template slot-scope="scope">
<span>{{types[scope.row.type]}}</span>
</template>
</el-table-column>
<el-table-column prop="creationTime" width="150" label="创建时间" align="center">
</el-table-column>
<el-table-column prop="startTime" width="150" label="起始时间" align="center">
<template slot-scope="scope">
<span>{{transferTime(scope.row.startTime,scope.row.type)}}</span>
</template>
</el-table-column>
<el-table-column prop="stopTime" width="150" label="结束时间" align="center">
<template slot-scope="scope">
<span>{{transferTime(scope.row.stopTime,scope.row.type)}}</span>
</template>
</el-table-column>
<el-table-column prop="surplusTime" label="倒计时" align="center">
<!-- <template slot-scope="scope">
<span v-if="scope.row.status == 2" v-countdown="scope.row.surplusTime">{{scope.row.surplusTime}}</span>
<span v-else>00:00:00</span>
</template> -->
</el-table-column>
<el-table-column label="实验状态" align="center">
<template slot-scope="scope">
<span>{{status[scope.row.status]}}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="170">
<template slot-scope="scope">
<template v-if="scope.row.status == 1">
<el-button type="text" @click="start(scope.row)" v-auth>启动</el-button>
<el-button type="text" @click="edit(scope.row)" v-auth>修改</el-button>
</template>
<template v-else-if="scope.row.status == 2">
<el-button type="text" @click="finish(scope.row)" v-auth>提前结束</el-button>
</template>
<template v-else-if="scope.row.status == 3">
<el-button type="text" @click="show(scope.row)" v-auth>查看成绩</el-button>
</template>
<el-button v-if="scope.row.status == 1 || scope.row.status == 3" type="text" @click="delData(scope.row)" v-auth>删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page"></el-pagination>
</div>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
systemList: Setting.systemList,
systemId: '',
keyword: '',
typeList: [
{
value: '',
name: '不限'
},
{
value: 1,
name: '手动发布'
},
{
value: 2,
name: '定时发布'
}
],
status: ['','待开始','进行中','已完成'],
types: ['','手动发布','定时发布'],
statusList: [
{
value: '',
name: '不限'
},
{
value: 1,
name: '待开始'
},
{
value: 2,
name: '进行中'
},
{
value: 3,
name: '已完成'
}
],
listData: [],
form: {
type: '',
status: '',
startTime: '',
stopTime: '',
month: '',
searchContent: ''
},
multipleSelection: [],
dateList: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '近一个月'
},
{
id: 3,
name: '近三个月'
},
{
id: 6,
name: '近六个月'
}
],
date: [],
page: 1,
pageSize: 10,
total: 0,
ruleIds: [],
timer: null
};
},
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 = `${util.formateTime(hours)}:${util.formateTime(minutes)}:${util.formateTime(seconds)}`
}else{
clearInterval(timer)
}
el.innerHTML = time
},1000)
that.timerList.push(timer)
}
}
},
computed: {
...mapState('user', [
'schoolId'
]),
},
watch: {
'form.month': function(val){
if(val){
let unit = 24 * 60 * 60 * 1000
this.date = [this.formatDate('yyyy-MM-dd',new Date(new Date().getTime() - unit * 30 * val)),this.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.stopTime = val[1]
}else{
this.form.startTime = ''
this.form.stopTime = ''
}
this.initData()
},
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
computed: {
role() {
return this.name === 'admin' ? '超级管理员' : '普通用户';
}
},
mounted() {
this.getData()
this.timer = setInterval(this.getData,1000)
this.$once('hook:beforeDestroy',() => {
clearInterval(this.timer)
})
},
methods: {
getData() {
let data = {
type: this.form.type,
startTime: this.form.startTime,
stopTime: this.form.stopTime,
month: this.form.month,
searchContent: util.encodeStr(this.keyword),
status: this.form.status,
page: this.page,
size: this.pageSize,
systemId: this.systemId,
schoolId: this.schoolId ? this.schoolId : ''
}
this.$get(this.api.expList,data).then(res => {
this.listData = res.list.list
this.total = res.list.totalCount
}).catch(res => {});
},
initData(){
this.$refs.table.clearSelection()
this.page = 1
this.getData()
},
add(){
this.$router.push('add')
},
edit(row){
this.$router.push(`add?id=${row.id}`)
},
show(row){
this.$router.push(`/achievement/ass?systemId=${this.systemId}&id=${row.id}&projectId=${row.projectId}&name=${row.projectName}&experimentalName=${row.experimentalName}&class=${row.experimentalClassName}`)
},
start(row){
let data = {
id: row.id,
startTime: this.formatDate("yyyy-MM-dd hh:mm:ss",new Date()),
status: 2
}
this.$post(this.api.expUpdate,data).then(res => {
if(res.errmessage == 'success') {
util.successMsg('启动成功!')
this.getData()
}
}).catch(res => {});
},
finish(row){
this.$confirm('确定要提前结束吗?', '提示', {
type: 'warning'
})
.then(() => {
let data = {
id: row.id,
stopTime: this.formatDate("yyyy-MM-dd hh:mm:ss",new Date()),
status: 3
}
this.$post(this.api.expUpdate,data).then(res => {
if(res.errmessage == 'success') {
util.successMsg('提前结束成功!')
this.getData()
}
}).catch(res => {})
})
.catch(() => {})
},
delData(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(this.api.expDelete,[row.id]).then(res => {
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.id
})
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
let data = delList
this.$post(this.api.expDelete,data).then(res => {
this.multipleSelection = [];
this.$refs.table.clearSelection()
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
}else{
util.errorMsg('请先选择数据 !');
}
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
onSearch(){
this.page = 1
this.getData()
},
handleCurrentChange(val) {
this.page = val;
this.getData();
},
transferTime(date,type){
if(date == '0000-00-00 00:00:00') return '---'
return date
}
}
};
</script>
<style lang="scss" scoped>
.el-radio-group{
white-space: nowrap;
}
</style>

@ -0,0 +1,631 @@
<template>
<div class="page">
<h6 class="p-title">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<label>题目类型</label>
<el-radio-group v-model="subject" @change="initData">
<el-radio
v-for="(item,index) in subjectList"
:key="index"
:label="item.id"
>{{item.name}}</el-radio>
</el-radio-group>
</li>
<li>
<el-input size="small" placeholder="请输入题干" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" size="small" @click="getInfo" v-auth>测评设置</el-button>
<el-button type="primary" size="small" @click="addTopics" v-auth>新增题目</el-button>
<el-button type="primary" size="small" @click="showBatchUpload" v-auth>批量上传</el-button>
<el-button type="primary" size="small" @click="delAllData" v-auth>批量删除</el-button>
</div>
</div>
<el-table :data="listData" ref="table" row-key="id" class="table" stripe header-align="center" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<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="questionStem" label="题干" align="center"></el-table-column>
<el-table-column prop="questionTypeName" label="题型" align="center"></el-table-column>
<el-table-column prop="modifyTime" label="时间" align="center"></el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<template v-if="scope.row.isEnable">
<el-button type="text" @click="showQues(scope.row)" v-auth>查看</el-button>
</template>
<template v-else>
<el-button type="text" @click="editQues(scope.row)" v-auth>修改</el-button>
</template>
<el-switch
v-model="scope.row.isEnable"
:active-text="scope.row.isEnable ? '关闭' : '启用'"
:active-value="1"
:inactive-value="0"
style="margin: 0 10px 0 5px"
@change="switchQues($event,scope.row,scope.$index)"
v-auth="'evaluation:禁用'"
></el-switch>
<el-button type="text" @click="delData(scope.row)" v-auth>删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="handleCurrentChange" :current-page="page" :page-size="pageSize" layout="total,prev, pager, next" :total="total"></el-pagination>
</div>
<el-dialog title="测评设置" :visible.sync="SetEvaluation" width="30%" :close-on-click-modal="false">
<div style="margin-bottom: 15px;">
<span class="radio">题目选择</span>
<el-radio v-model="info.evaluationType" label="1">随机</el-radio>
<el-radio v-model="info.evaluationType" label="0">自定义</el-radio>
</div>
<!-- 随机 -->
<el-card shadow="hover" class="card_m" v-show="info.evaluationType==1">
<div class="input flex_around">
<span>测评题目总数</span>
<el-input placeholder="请输入题目数量" type="number" v-model="info.questionNum"></el-input>
<span>(总数{{info.totalQuestionNum}})</span>
</div>
</el-card>
<!-- 自定义 -->
<el-card shadow="hover" class="card_m" v-show="info.evaluationType==0">
<div class="input">
<div class="check-wrap" :class="{checked: info.isSingleEnable}">
<el-checkbox v-model="info.isSingleEnable">单选题</el-checkbox>
<el-input placeholder="请输入题目数量" type="number" v-model="info.singleNum" :disabled="!info.isSingleEnable"></el-input>
<span>(总数{{info.totalSingleNum}})</span>
</div>
<div class="check-wrap" :class="{checked: info.isMultipleEnable}">
<el-checkbox v-model="info.isMultipleEnable">多选题</el-checkbox>
<el-input placeholder="请输入题目数量" type="number" v-model="info.multipleNum" :disabled="!info.isMultipleEnable"></el-input>
<span>(总数{{info.totalMultipleNum}})</span>
</div>
<div class="check-wrap" :class="{checked: info.isJudgmentEnable}">
<el-checkbox v-model="info.isJudgmentEnable">判断题</el-checkbox>
<el-input placeholder="请输入题目数量" type="number" v-model="info.judgmentNum" :disabled="!info.isJudgmentEnable"></el-input>
<span>(总数{{info.totalJudgmentNum}})</span>
</div>
</div>
</el-card>
<div class="jobNumber">
<div class="input">
<span style="margin:0px 15px 0px 35px">测评时长</span>
<el-input placeholder="请输入时间" type="number" v-model="info.duration"></el-input>
<span style="margin-left:15px">分钟</span>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="SetEvaluation = false"> </el-button>
<el-button size="small" type="primary" @click="submitSetEva"> </el-button>
</span>
</el-dialog>
<el-dialog :title="topicsTitle" :visible.sync="NewTopics" width="30%" @close="closeTopics" :close-on-click-modal="false">
<el-form
:model="topicForm"
:rules="rules"
:disabled="isShowTopics"
ref="topicForm"
label-width="70px"
class="demo-topicForm"
>
<el-form-item label="题型" prop="questionType">
<el-radio-group v-model="topicForm.questionType" @change="questionTypeChange">
<el-radio label="单选题"></el-radio>
<el-radio label="多选题"></el-radio>
<el-radio label="判断题"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="题干" prop="questionStem">
<el-input type="textarea" v-model="topicForm.questionStem"></el-input>
</el-form-item>
<el-form-item label="选项" prop="optionA">
<div class="input flex_around bt">
<span>A</span>
<el-input placeholder="请输入题目" v-model="topicForm.optionA"></el-input>
<el-checkbox v-model="topicForm.aisTrue">设为正确答案</el-checkbox>
</div>
<div class="input flex_around bt">
<span>B</span>
<el-input placeholder="请输入题目" v-model="topicForm.optionB"></el-input>
<el-checkbox v-model="topicForm.bisTrue">设为正确答案</el-checkbox>
</div>
<template v-if="topicForm.questionType != '判断题'">
<div class="input flex_around bt">
<span>C</span>
<el-input placeholder="请输入题目" v-model="topicForm.optionC"></el-input>
<el-checkbox v-model="topicForm.cisTrue">设为正确答案</el-checkbox>
</div>
<div class="input flex_around bt">
<span>D</span>
<el-input placeholder="请输入题目" v-model="topicForm.optionD"></el-input>
<el-checkbox v-model="topicForm.disTrue">设为正确答案</el-checkbox>
</div>
<div class="input flex_around bt">
<span>E</span>
<el-input placeholder="请输入题目" v-model="topicForm.optionE"></el-input>
<el-checkbox v-model="topicForm.eisTrue">设为正确答案</el-checkbox>
</div>
<div class="input flex_around">
<span>F</span>
<el-input placeholder="请输入题目" v-model="topicForm.optionF"></el-input>
<el-checkbox v-model="topicForm.fisTrue">设为正确答案</el-checkbox>
</div>
</template>
</el-form-item>
<el-form-item label="答案解析" prop="answerAnalysis">
<el-input type="textarea" v-model="topicForm.answerAnalysis"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" v-show="!isShowTopics">
<el-button size="small" @click="NewTopics = false"> </el-button>
<el-button size="small" type="primary" @click="saveTopics"> </el-button>
</div>
</el-dialog>
<el-dialog title="批量上传" :visible.sync="BatchUpload" width="30%" @close="closeUpload" :close-on-click-modal="false">
<el-card shadow="hover" class="card_m" v-show="this.label=1">
<div class="Upload">
<div class="bt" @click="downloadTem">
<el-link :underline="false">
1.请下载模板
<i class="el-icon-download"></i>
</el-link>
</div>
<div>
<el-upload
accept=".xls,.xlsx"
:on-remove="handleDataRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:action="this.api.import"
:file-list="uploadDataList"
name="file"
>
<el-link :underline="false">
2.请点击批量导入
<i class="el-icon-upload"></i>
</el-link>
</el-upload>
<el-link v-if="uploadFaild" type="primary" @click="showFaild">部分数据导入失败查看失败原因</el-link>
</div>
</div>
</el-card>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="BatchUpload = false"> </el-button>
<el-button size="small" type="primary" @click="uploadSure"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import util from '@/libs/util'
import Setting from '@/setting'
export default {
data() {
return {
topicForm: {
answer: '',
questionType : '单选题',
questionStem : '',
optionA:'',
optionB:'',
optionC:'',
optionD:'',
optionE:'',
optionF:'',
aisTrue: false,
bisTrue: false,
cisTrue: false,
disTrue: false,
eisTrue: false,
fisTrue: false,
answerAnalysis: ''
},
rules: {
questionType: [{ required: true, message: '请选择题型', trigger: 'change' }],
questionStem: [{ required: true, message: '请填写题干', trigger: 'blur' }],
// optionA: [{ required: true, message: '', trigger: 'change' }],
// optionB: [{ required: true, message: '', trigger: 'change' }]
},
value: true,
subject: '', //
keyword: '',
listData: [],
subjectList: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '单选题'
},
{
id: 2,
name: '多选题'
},
{
id: 3,
name: '判断题'
}
],
page: 1,
pageSize: 10,
total: 0,
SetEvaluation: false,
radio: '1', //
topicsNumber: '', //
topicsTime: '', //
random: true,
custom: false,
info: {},
NewTopics: false, //
Customs: ['1', '2', '3'],
BatchUpload: false, //
questionType: ['','单选题','多选题','判断题'],
multipleSelection: [],
isShowTopics: false,
topicsTitle: '',
uploadList: [],
uploadDataList: [],
searchTimer: null,
uploadFaild: false,
token: ''
};
},
mounted() {
this.getData()
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
methods: {
getData() {
this.$get(this.api.list, {
page: this.page,
size: this.pageSize,
questionStem: util.encodeStr(this.keyword),
questionType: this.subject
})
.then(res => {
this.listData = res.page.list
this.total = res.page.totalCount
})
.catch(err => {})
},
initData(){
this.page = 1
this.getData()
this.$refs.table.clearSelection()
},
resetForm() {
this.topicForm = {
answer: '',
questionType : '',
questionStem : '',
optionA:'',
optionB:'',
optionC:'',
optionD:'',
optionE:'',
optionF:'',
aisTrue: false,
bisTrue: false,
cisTrue: false,
disTrue: false,
eisTrue: false,
fisTrue: false,
answerAnalysis: ''
}
this.$nextTick(() => {
this.$refs.topicForm.clearValidate()
})
},
handleCurrentChange(val) {
this.page = val
this.getData()
},
addTopics() {
this.topicForm.id = ''
this.topicsTitle = '新增题目'
this.NewTopics = true
},
getDetail(id) {
this.$get(this.api.infoId + id).then(res => {
this.topicForm = res.questions
this.topicForm.id = id
this.topicForm.questionType = this.questionType[this.topicForm.questionType]
this.NewTopics = true
}).catch(res => {});
},
editQues(row) {
this.topicsTitle = '编辑题目'
this.getDetail(row.id)
},
showQues(row) {
this.topicsTitle = '查看题目'
this.isShowTopics = true
this.getDetail(row.id)
},
closeTopics() {
this.isShowTopics = false
this.resetForm()
},
switchQues(val,row,index) {
this.$put(this.api.isenable, [row.id])
.then(res => {
if(res.status == 400){
util.errorMsg(res.errmessage)
row.isEnable = row.isEnable == 1 ? 0 : 1
}
})
.catch(err => {});
},
delData(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(this.api.delete,[row.id]).then(res => {
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.id
})
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
let data = delList
this.$post(this.api.delete,data).then(res => {
this.multipleSelection = [];
this.$refs.table.clearSelection()
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
}else{
util.errorMsg('请先选择题目 !');
}
},
downloadTem() {
location.href = this.api.questionsTemplate
},
getInfo() {
this.$get(this.api.info).then(res => {
this.info = res.data
this.info.evaluationType = this.info.evaluationType.toString()
this.info.isSingleEnable = Boolean(this.info.isSingleEnable)
this.info.isMultipleEnable = Boolean(this.info.isMultipleEnable)
this.info.isJudgmentEnable = Boolean(this.info.isJudgmentEnable)
this.SetEvaluation = true
}).catch(res => {});
},
questionTypeChange() {
for(let i in this.topicForm){
if(i.includes('isTrue')) this.topicForm[i] = false
}
},
submitSetEva() {
let info = this.info
if(info.evaluationType == 0){
let allEmpty = true
if(!info.isSingleEnable && !info.isMultipleEnable && !info.isJudgmentEnable) return this.$message.warning('请至少选择一种题型')
if(info.isSingleEnable == 1 && info.singleNum != 0) allEmpty = false
if(info.isMultipleEnable == 1 && info.multipleNum != 0) allEmpty = false
if(info.isJudgmentEnable == 1 && info.judgmentNum != 0) allEmpty = false
if(allEmpty) return this.$message.warning('请至少选中一种类型,并数量大于0')
if(info.isSingleEnable == 1 && info.singleNum > info.totalSingleNum) return this.$message.warning('单选题大于总数,请重新输入')
if(info.isMultipleEnable == 1 && info.multipleNum > info.totalMultipleNum) return this.$message.warning('多选题大于总数,请重新输入')
if(info.isJudgmentEnable == 1 && info.judgmentNum > info.totalJudgmentNum) return this.$message.warning('判断题大于总数,请重新输入')
}else{
if(info.questionNum === '') return this.$message.warning('请输入测评题目总数')
if(info.questionNum == 0) return this.$message.warning('测评题目总数不得为0')
}
if(info.duration === '') return this.$message.warning('请输入测评时长')
if(info.duration == 0) return this.$message.warning('测评时长不得为0')
this.info.isSingleEnable = Number(this.info.isSingleEnable)
this.info.isMultipleEnable = Number(this.info.isMultipleEnable)
this.info.isJudgmentEnable = Number(this.info.isJudgmentEnable)
this.$put(this.api.update,this.info).then(res => {
if(res.errmessage == 'success'){
util.successMsg('提交成功!');
this.SetEvaluation = false
}else{
util.errorMsg(res.message);
}
}).catch(res => {});
},
saveTopics() {
this.$refs.topicForm.validate((valid) => {
if (valid) {
let topicForm = this.topicForm
let optionCount = 0
let answer = ''
let isInvalidAnswer = false
for(let n in topicForm) {
if(n.includes('option')) {
topicForm[n] != '' && ++optionCount
}
if(n.includes('isTrue') && topicForm[n]) {
let curOpt = n.replace('isTrue','')
answer += curOpt
if(!topicForm[`option${curOpt.toUpperCase()}`].length) isInvalidAnswer = true
}
}
if(optionCount < 2) return this.$message.warning('请至少添加两个选项!');
if(!answer) return this.$message.warning('请设置正确答案!');
if(topicForm.questionType != '多选题' && answer.length > 1) return this.$message.warning('单选题、判断题只能设置一个正确答案!');
if(isInvalidAnswer) return this.$message.warning('正确答案选项为空,请重新设置!');
this.topicForm.questionType = this.questionType.indexOf(this.topicForm.questionType)
this.topicForm.answer = answer.toUpperCase()
if(this.topicForm.id) {
this.$put(this.api.questionsUpdate,this.topicForm).then(res => {
if(res.errmessage == 'success') {
util.successMsg('提交成功!');
this.NewTopics = false
this.getData()
}else{
util.errorMsg(res.message);
}
}).catch(res => {});
}else{
this.$post(this.api.save,this.topicForm).then(res => {
if(res.errmessage == 'success') {
util.successMsg('提交成功!');
this.NewTopics = false
this.getData()
}else{
util.errorMsg(res.message);
}
}).catch(res => {});
}
}else{
return false;
}
})
},
showBatchUpload() {
this.BatchUpload = true
},
handleExceed(files, fileList) {
this.$message.warning(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
this.uploadFaild = false
if(res.data.token){
this.token = res.data.token
this.uploadFaild = true
}
},
showFaild(){
location.href = `${this.api.export_failure}?token=${this.token}`
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
this.uploadList = fileList
},
handleDataRemove(file, fileList) {
this.uploadList = fileList
this.uploadFaild = false
},
uploadSure(){
this.BatchUpload = false
this.page = 1
this.keyword = ''
this.getData()
},
closeUpload() {
this.uploadFaild = false
this.uploadList = []
this.uploadDataList = []
}
}
};
</script>
<style lang="scss" scoped>
::v-deep .el-checkbox-group{
font-size: 2px;
}
.Upload {
text-align: center;
}
.bt {
margin-bottom: 15px;
}
.bt_one {
margin-left: 10px;
}
.Bank_m {
margin-bottom: 20px;
}
.Bank img {
width: 15px;
height: 15px;
margin-right: 10px;
}
.Bank span {
font-size: 16px;
}
.jobNumber {
margin: 10px 0;
}
.flex_around {
display: flex;
justify-content: space-around;
align-items: center;
}
.card_m {
margin: 10px 0 20px 0;
}
.input ::v-deep .el-input {
width: 50%;
}
.radio {
margin: 0 15px 0 30px;
font-weight: 600;
}
.mag {
margin-right: 20px;
}
.check-wrap{
display: flex;
align-items: center;
margin-bottom: 15px;
}
.check-wrap .el-input{
margin: 0 15px;
}
.check-wrap.checked{
color: #9076FF;
}
</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>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,393 @@
<template>
<div class="page">
<el-page-header class="m-b-20" content="实验项目管理" @back="goBack"></el-page-header>
<h6 class="p-title">筛选</h6>
<div class="tool mul">
<ul class="filter">
<li>
<label>创建人</label>
<el-select size="small" v-model="queryData.founder" clearable placeholder="请选择创建人" @change="initData">
<el-option v-for="(item,index) in founder" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</li>
<li>
<label>状态</label>
<el-select size="small" v-model="queryData.state" clearable placeholder="请选择状态" @change="initData">
<el-option v-for="(item,index) in state" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</li>
<li>
<label>权限</label>
<el-select size="small" v-model="queryData.projectPermissions" placeholder="请选择" @change="initData">
<el-option
v-for="item in projectPermissions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</li>
<li>
<label>系统</label>
<el-select size="small" v-model="systemId" placeholder="请选择" @change="initData">
<el-option
v-for="item in systemList"
:key="item.value"
:label="item.label"
:value="item.id"
></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-button type="primary" size="small" @click="add" v-auth>新增项目</el-button>
<el-button type="primary" size="small" @click="delAllData" v-auth>批量删除</el-button>
</div>
</div>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"></el-table-column>
<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="projectName" label="实验项目名称" align="center">
</el-table-column>
<el-table-column prop="founder" label="创建人" align="center"></el-table-column>
<el-table-column label="权限" align="center">
<template slot-scope="scope">
{{scope.row.projectPermissions == 2 ? '竞赛' : projectPermissions.find(n => n.value === scope.row.projectPermissions).label}}
</template>
</el-table-column>
<el-table-column prop="creationTime" label="创建时间" align="center">
</el-table-column>
<el-table-column prop="status" label="状态" align="center">
<template slot-scope="scope">
{{transferStatus(scope.row.state)}}
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" @click="edit(scope.row)" v-auth v-if="roleId == 1 || (roleId == 13 && scope.row.founder != '超级管理员') || (roleId == 14 && scope.row.founder == '老师')">编辑</el-button>
<el-button type="text" @click="delData(scope.row)" v-auth v-if="roleId == 1 || (roleId == 13 && scope.row.founder != '超级管理员') || (roleId == 14 && scope.row.founder == '老师')">删除</el-button>
<el-button type="text" @click="copyData(scope.row)" v-auth>复制</el-button>
<el-switch
v-model="scope.row.enable"
:active-text="scope.row.enable ? '关闭' : '启用'"
:active-value="0"
:inactive-value="1"
style="margin: 0 10px 0 10px"
@change="switchOff($event,scope.row,scope.$index)"
></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="handleCurrentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
<el-dialog title="复制" :visible.sync="copyVisible" width="24%" center :close-on-click-modal="false">
<el-form>
<el-form-item>
<el-input placeholder="请输入项目名称" v-model="projectName" @change="projectNameExistis"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="copyVisible = false"> </el-button>
<el-button type="primary" @click="copySubmit"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
showBack: JSON.stringify(this.assFields) == '{}' ? false : true,
roleIdEd: this.roleId ? 13 : this.roleId,// roleId13roleId14113,1413.>
systemId: '',
systemList: Setting.systemList,
queryData: {
projectPermissions: "",
founder: "",
state: "",
projectName: "",
},
keyword: '',
status: '',
listData:[],
total: 0,
projectPermissions: [
{
value: "",
label: "不限"
},
{
value: 0,
label: "练习"
},
{
value: 1,
label: "考核"
},
// {
// value: 2,
// label: ""
// }
],
founder: [
{
value: "",
label: "不限"
},
{
value: 1,
label: "超级管理员"
},
{
value: 13,
label: "管理员"
},
{
value: 14,
label: "老师"
}
],
state: [
{
value: "",
label: "不限"
},
{
value: 0,
label: "草稿箱"
},
{
value: 1,
label: "已发布"
}
],
page: 1,
pageSize: 10,
multipleSelection: [],
copyVisible: false,
projectName: '',
projectNameRepeat: false,
currentRow: {},
listDataAll: []
};
},
computed: {
...mapState('user', [
'userId','roleId'
]),
...mapState('project', [
'lastSystemId','assFields'
]),
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted() {
this.systemId = this.lastSystemId ? this.lastSystemId : Setting.systemId
console.log(this.systemId,'外面的sysid');
this.getData()
},
methods: {
...mapActions('project', [
'setSystemId'
]),
getData(){
this.setSystemId(this.systemId)
let data = this.queryData
data.userId = this.userId
data.systemId = this.systemId
data.pageNo = this.page
data.pageSize = this.pageSize
data.projectName = util.encodeStr(this.keyword)
data.systemId = this.systemId
this.$get(this.api.queryAllManagements,data).then(res => {
let list = res.pageInfo.list
let newList = []
list.map(n => {
if(n.founder.includes(',')){
n.founder = '管理员'
}else{
n.founder = util.getRoleName(n.founder)
}
})
this.listData = list
this.total = res.pageInfo.total
}).catch(res => {});
},
initData(){
this.page = 1
this.getData()
},
handlePage(){
let list = this.listDataAll
let result = list.slice((this.page - 1) * this.pageSize,this.page * this.pageSize)
this.listData = result
},
transferStatus(status){
return status == 1 ? '已发布' : '草稿箱'
},
handleCurrentChange(val){
this.page = val
this.getData()
},
add(){
this.setSystemId(this.systemId)
this.$router.push('add')
},
edit(row){
console.log(row,'编辑触发');
this.setSystemId(row.systemId)
this.$router.push(`add?id=${row.projectId}`)
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delData(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(this.api.removeProjectManagement,[row.projectId]).then(res => {
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.projectId
})
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(this.api.removeProjectManagement,delList).then(res => {
this.multipleSelection = [];
this.$refs.table.clearSelection()
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
}else{
util.errorMsg('请先选择项目 !');
}
},
projectNameExistis(){
let data = {
projectName: util.encodeStr(this.projectName)
}
this.$get(this.api.isNameExistis,data).then(res => {
if(res.status != 200){
this.projectNameRepeat = true
this.$message.warning('该项目名称已存在')
}else{
this.projectNameRepeat = false
}
}).catch(res => {})
},
copyData(row){
this.currentRow.management = {
caseDescription: row.caseDescription,
experimentSuggests: row.experimentSuggests,
experimentalGoal: row.experimentalGoal,
founder: row.founder,
isstartexperimentSuggests: row.isstartexperimentSuggests,
isstartexperimental: row.isstartexperimental,
projectName: row.projectName,
projectPermissions: row.projectPermissions,
state: row.state,
systemId: row.systemId,
userId: row.userId,
knowledgePoints: row.knowledgePoints,
experimentIntroduction: row.experimentIntroduction
}
this.currentRow.founder = row.founder
this.projectName = row.projectName
this.projectNameRepeat = true
this.copyVisible = true
let data = {
projectId: row.projectId
}
this.$get(this.api.getZZJudgmentPoints,data).then((res) => {
this.currentRow.roleId = res.message.roleList.map(n => n.roleId)
let scoreList = res.message.scoreIndexList
let scores = []
for(let i in scoreList){
scores = scores.concat(scoreList[i])
}
let point = res.message.judgmentPointsList
point.map(n => {
let same = scores.find(e => e.judgmentPointsId == n.judgmentPointsId)
if(same) n.score = same.score
})
this.currentRow.pooints = point
this.$message.warning('请修改项目名称')
})
},
copySubmit(){
if(!this.projectName.length) return this.$message.warning('请填写项目名称')
if(this.projectNameRepeat) return this.$message.warning('该项目名称已存在')
let data = this.currentRow
data.management.projectName = this.projectName
data.founder = this.roleId
data.management.founder = this.roleId
data.management.userId = this.userId
data.pooints.map(n => {
n.userId = this.userId
})
let systemId = this.currentRow.management.systemId
let url = this.api.addProjectManagement
if(systemId == 2 || systemId == 3) url = this.api.addProjectManagementTrad
this.$post(url,data).then((res) => {
util.successMsg('复制成功');
this.copyVisible = false
this.getData()
})
},
switchOff(val,row,index) {
this.$get(this.api.enableProject,{
id: row.projectId,
enable: row.enable
})
.then(res => {
if(res.status != 200){
util.errorMsg(res.errmessage)
row.enable = row.enable == 1 ? 0 : 1
}
})
.catch(err => {});
},
goBack() {
this.$router.back()
},
}
};
</script>
<style lang="scss" scoped>
</style>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,527 @@
<template>
<div class="page">
<h6 class="p-title">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<el-input style="width: 250px;" size="small" placeholder="请输入学生账号/姓名/学校名称" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" size="small" v-auth @click="addStudent">新增学生</el-button>
<el-button type="primary" size="small" v-auth @click="batchImport">批量导入</el-button>
<el-button type="primary" size="small" v-auth @click="delAllSelection">批量删除</el-button>
</div>
</div>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange" :row-key="getRowKeys">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center">
</el-table-column>
<el-table-column prop="account" label="账号" align="center">
</el-table-column>
<el-table-column prop="schoolName" label="院校" align="center">
</el-table-column>
<el-table-column prop="workNumber" label="学号" align="center">
</el-table-column>
<el-table-column prop="userName" label="学生姓名" align="center">
</el-table-column>
<el-table-column prop="countries" label="账号角色" align="center">
<template slot-scope="scope">学生</template>
</el-table-column>
<el-table-column prop="loginNumber" label="登录次数" align="center">
</el-table-column>
<el-table-column prop="lastLoginTime" label="上次登录时间" align="center">
</el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button type="text" v-auth @click="editStudent(scope.row,true)">查看</el-button>
<el-button type="text" v-auth @click="editStudent(scope.row,false)">编辑</el-button>
<el-button type="text" v-auth @click="resetPassword(scope.row)">重置密码</el-button>
<el-button type="text" v-auth @click="handleDelete(scope.row)">删除</el-button>
<el-switch
v-model="scope.row.disableAccount"
:active-value="0"
:inactive-value="1"
style="margin: 0 5px"
@change="switchOff($event,scope.row,scope.$index)"
v-auth="'学生管理:禁用'"
></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
<el-dialog :title="isDetail ? '查看学生' : (isAdd ? '新增学生' : '编辑学生')" :visible.sync="studentVisible" width="30%" @close="closeStudent" class="dialog" :close-on-click-modal="false">
<el-form ref="form" :model="form" :rules="rules" :disabled="isDetail" label-width="100px">
<el-form-item prop="account" label="学生账号">
<el-input v-model="form.account" placeholder="请输入学生账号" @change="accountChange"></el-input>
</el-form-item>
<el-form-item prop="userName" label="学生姓名">
<el-input v-model="form.userName" placeholder="请输入学生姓名"></el-input>
</el-form-item>
<el-form-item prop="roleId" label="账号角色">
学生
</el-form-item>
<el-form-item prop="workNumber" label="学生学号">
<el-input v-model="form.workNumber" placeholder="" @change="worknumberChange"></el-input>
</el-form-item>
<el-form-item prop="phone" label="手机号">
<el-input v-model="form.phone" placeholder="可用于登录平台,以及找回密码" maxlength="11" @change="phoneChange"></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model="form.email" placeholder="可用于登录平台,以及找回密码"></el-input>
</el-form-item>
<el-form-item prop="schoolId" label="所在院校">
<el-select v-model="form.schoolId" placeholder="默认为当前院校(可修改)" filterable disabled @change="worknumberChange">
<el-option v-for="(item,index) in schoolList" :key="index" :label="item.schoolName" :value="item.schoolId"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="uniqueIdentificationAccount" label="唯一标识">
<el-input disabled v-model="form.uniqueIdentificationAccount"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer" v-if="!isDetail">
<el-button size="small" @click="studentVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="saveData"> </el-button>
</span>
</el-dialog>
<el-dialog title="批量导入" :visible.sync="importVisible" width="24%" :close-on-click-modal="false">
<div style="text-align: center">
<div style="margin-bottom: 10px;"><el-button type="primary" @click="downLoad">模板下载<i class="el-icon-download el-icon--right"></i></el-button></div>
<el-upload
accept=".xls,.xlsx"
:on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:action="this.api.uploadFile"
:file-list="uploadList"
name="file"
>
<el-button type="primary" class="ml20">上传文件<i class="el-icon-upload2 el-icon--right"></i></el-button>
</el-upload>
<el-link v-if="uploadFaild" type="primary" @click="showFaild">部分数据导入失败查看失败原因</el-link>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="importVisible = false"> </el-button>
<el-button size="small" type="primary" @click="uploadSure"> </el-button>
</span>
</el-dialog>
<el-dialog title="重置密码" :visible.sync="passwordVisible" :close-on-click-modal="false" @close="closePassword" width="30%">
<el-form ref="passwordForm" :model="form" label-width="60px">
<el-form-item label="原密码">
<el-input type="password" v-model="passwordForm.password" placeholder="请输入原密码"></el-input>
</el-form-item>
<el-form-item label="新密码">
<el-input type="password" v-model="passwordForm.newPassword" placeholder="请输入新密码" @keyup.enter.native="editPassword"></el-input>
</el-form-item>
<el-form-item label="新密码">
<el-input type="password" v-model="passwordForm.reNewPassword" placeholder="请确认新密码" @keyup.enter.native="editPassword"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="passwordVisible = false"> </el-button>
<el-button size="small" type="primary" @click="editPassword"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
isDetail: false,
keyword: '',
schoolId: Setting.schoolId,
form: {
userName: '',
account: '',
phone: '',
uniqueIdentificationAccount: '',
workNumber: '',
email: '',
account: '',
roleId: 4,
schoolId: this.schoolId,
schoolAppellationId: this.schoolId
},
rules: {
account: [
{ required: true, message: '请输入账号', trigger: 'blur' },
{
pattern: /^[A-Za-z0-9]*$/,
message: '请输入正确的账号',
trigger: 'blur'
}
],
userName: [
{ required: true, message: '请输入学生姓名', trigger: 'blur' }
],
schoolId: [
{ required: true, message: '请选择所在院校', trigger: 'change' }
],
// uniqueIdentificationAccount: [
// { required: true, message: '', trigger: 'blur' },
// ],
workNumber: [
{ required: true, message: '请输入学生学号', trigger: 'blur' },
{
pattern: /^[A-Za-z0-9]*$/,
message: '请输入正确的学号',
trigger: 'blur'
}
],
phone: [
// { required: true, message: '', trigger: 'blur' },
{
pattern: /^1[3456789]\d{9}$/,
message: '请输入正确的手机号',
trigger: 'blur'
}
],
email: [
// { required: true, message: '', trigger: 'blur' },
{
pattern: /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/,
message: '请输入正确的邮箱',
trigger: 'blur'
}
]
},
listData:[],
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
uploadList: [],
importVisible: false,
isAdd: true,
studentVisible: false,
accountReapeat: false,
phoneRepeat: false,
workNumberReapeat: false,
isDetail: false,
resetVisible: false,
passwordVisible: false,
passwordForm: {
password: '',
newPassword: '',
reNewPassword: ''
},
schoolList: [],
uploadFaild: false,
token: '',
accountMsg: ''
};
},
mounted() {
this.form.schoolId = this.schoolId
this.form.schoolAppellationId = this.schoolId
this.getData()
this.getSchoolData()
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
methods: {
getData() {
let data = {
schoolId: this.schoolId,
seachContent: util.encodeStr(this.keyword),
page: this.page,
size: this.pageSize
}
this.$get(this.api.queryStudent,data).then(res => {
this.listData = res.data.list
this.total = res.data.totalCount
}).catch(res => {});
},
initData(){
this.$refs.table.clearSelection()
this.page = 1
this.getData()
},
saveData() {
this.$refs.form.validate((valid) => {
if (valid) {
if(this.accountReapeat) return this.$message.warning(this.accountMsg)
if(this.workNumberReapeat) return this.$message.warning('该学生学号已存在')
if(this.phoneRepeat) return this.$message.warning('该手机号已存在')
this.form.schoolName = this.schoolList.find(n => n.schoolId == this.form.schoolId).schoolName
if(this.form.studentId) {
this.$put(this.api.updateStudent,this.form).then(res => {
if(res.errmessage == 'success') {
util.successMsg('提交成功!');
this.studentVisible = false
this.getData()
}else{
util.errorMsg(res.message);
}
}).catch(res => {});
}else{
this.form.uniqueIdentificationAccount = new Date().getTime()
this.$post(this.api.addStudent,this.form).then(res => {
if(res.errmessage == 'success') {
util.successMsg('提交成功!');
this.studentVisible = false
this.getData()
}else{
util.errorMsg(res.message);
}
}).catch(res => {});
}
}else{
return false;
}
})
},
async accountChange(){
let res = await this.$get(this.api.queryAccountIsExist, {
account: util.encodeStr(this.form.account),
schoolId: this.schoolId
});
if(res.message.user.length){
let roleId = res.message.user[0].roleId
if(roleId){
this.accountMsg = roleId == 4 ? '该账号已存在' : (roleId.includes(',') ? '该账号已绑定老师和管理员' : `该账号已绑定${util.getRoleName(roleId)}`)
}else{
this.accountMsg = '该账号已存在'
}
this.$message.warning(this.accountMsg)
this.accountReapeat = true
}else{
this.accountReapeat = false
}
},
async worknumberChange(){
let res = await this.$get(this.api.queryWorkNumberIsExist, {
workNumber: util.encodeStr(this.form.workNumber),
roleId: 4,
schoolId: this.schoolId
});
if(JSON.stringify(res.message) != '{}'){
this.$message.warning('该学生学号已存在');
this.workNumberReapeat = true
}else{
this.workNumberReapeat = false
}
},
async phoneChange(){
let res = await this.$get(this.api.queryPhone, { phone: this.regForm.phone });
if(res.message.length != 0){
this.$message.warning('该手机号已存在');
this.phoneRepeat = true
}else{
this.phoneRepeat = false
}
},
batchImport(){
this.importVisible = true
this.uploadList = []
this.uploadFaild = false
},
// /
getSchool(){
this.clearcity()
this.getSchoolData()
this.page = 1
this.getData()
},
getSchoolData(){
let data = {
schoolName: '',
provinceId: '',
cityId: ''
}
this.$get(this.api.querySchool,data).then(res => {
this.schoolList = res.message
}).catch(res => {});
},
closeStudent(){
this.isDetail = false
this.$refs.form.clearValidate()
this.form = {
schoolId: this.schoolId,
userName: '',
account: '',
phone: '',
uniqueIdentificationAccount: '',
workNumber: '',
email: '',
account: '',
roleId: 4,
schoolAppellationId: this.schoolId
}
},
currentChange(val) {
this.page = val;
this.getData();
},
addStudent(){
this.isAdd = true
this.studentVisible = true
},
editStudent(row,isDetail){
this.isAdd = false
this.isDetail = isDetail
this.studentVisible = true
this.form = Object.assign({},row)
this.$nextTick(() => {
this.$refs.form.clearValidate()
})
},
downLoad(){
location.href = this.api.studentTemplate
},
handleDelete(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(this.api.daleteStudent,[row.studentId]).then(res => {
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
getRowKeys(row) {
return row.userId;
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delAllSelection() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.studentId
})
this.$confirm('确定要删除选中用户吗?', '提示', {
type: 'warning'
})
.then(() => {
let data = delList
this.$post(this.api.daleteStudent,data).then(res => {
this.multipleSelection = [];
this.$refs.table.clearSelection()
util.successMsg('删除成功');
this.getData()
}).catch(res => {});
}).catch(() => {});
}else{
util.errorMsg('请先选择数据 !');
}
},
resetPassword(row){
this.$confirm(`重置后的密码为:${this.$config.initialPassword},确定重置?`, '提示', {
}).then(() => {
this.$put(this.api.reSetPassword,[row.userId]).then(res => {
if(res.errmessage == 'success') util.successMsg('重置成功')
}).catch(res => {});
}).catch(() => {
});
},
switchOff(val,row,index) {
console.log(11,val,row)
let data = {
studentId: row.studentId,
disableAccount: row.disableAccount ? 0 : 1
}
this.$put(this.api.disableAccount,data)
.then(res => {})
.catch(err => {});
},
closePassword() {
this.passwordForm = {
password: '',
newPassword: '',
reNewPassword: ''
}
},
editPassword(){
if(!this.passwordForm.password) return this.$message.warning('请输入原密码')
if(!this.passwordForm.newPassword) return this.$message.warning('请输入新密码')
if(!this.passwordForm.reNewPassword) return this.$message.warning('请确认新密码')
if(this.passwordForm.newPassword.length < 6 || this.passwordForm.reNewPassword.length < 6) return this.$message.warning('请输入6位数以上的密码')
if(this.passwordForm.newPassword !== this.passwordForm.reNewPassword) return this.$message.warning('输入的新密码不一致,请重新确认')
if(this.passwordForm.password === this.passwordForm.newPassword) return this.$message.warning('原密码跟新密码不能一致')
let data = this.passwordForm
data.userid = this.userId
this.$put(this.api.reSetPassword,data)
.then(res => {
if(res.errmessage == 'success'){
util.successMsg('更换成功')
this.passwordVisible = false
}
})
.catch(err => {
console.log(err);
});
},
//
handleExceed(files, fileList) {
this.$message.warning(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
showFaild(){
location.href = `${this.api.export_failureStudent}?token=${this.token}`
},
uploadSuccess(res, file, fileList) {
this.uploadFaild = false
if(res.errmessage == 'success'){
if(res.data.token){
this.token = res.data.token
this.uploadFaild = true
}else{
util.successMsg('上传成功')
}
}else{
res.message ? util.errorMsg(res.message) : util.errorMsg('上传失败,请检查数据')
}
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
this.uploadList = fileList
this.uploadFaild = false
},
uploadSure(){
this.importVisible = false
this.page = 1
this.keyword = ''
this.getData()
},
}
};
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,61 @@
<template>
<div class="page" style="padding: 0">
<div class="tabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == active}" @click="tabChange(index)">{{item}}</a>
</div>
<staff v-if="active == 'staff'" v-auth="'系统设置:员工管理'"></staff>
<role v-else v-auth="'系统设置:角色权限'"></role>
</div>
</template>
<script>
import Setting from '@/setting'
import { mapState } from 'vuex'
import staff from './staff'
import role from './role'
export default {
data() {
return {
active: 'staff',
tabs: {
staff: '员工管理',
role: '角色权限'
},
};
},
computed: {
...mapState('auth', [
'btns'
])
},
components: {
staff,
role
},
created() {
Setting.dynamicRoute && this.initTabs()
},
methods: {
tabChange(index){
this.active = index
},
initTabs(){
let btnPermissions = this.routes
let tab1 = btnPermissions.includes('系统设置:员工管理')
let tab2 = btnPermissions.includes('系统设置:角色权限')
if(!tab1){
delete this.tabs.staff
}
if(!tab2){
delete this.tabs.role
}
}
}
};
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,307 @@
<template>
<div class="page">
<div class="tool">
<ul class="filter">
<li>
<el-input size="small" placeholder="请输入角色名称" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</li>
</ul>
<div>
<!-- <el-button type="primary" size="small" round @click="addRole" v-auth="'system:角色权限:新增角色'">新增角色</el-button>
<el-button type="primary" size="small" round @click="delAllSelection" v-auth="'system:角色权限:批量删除'">批量删除</el-button> -->
</div>
</div>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange" :row-key="getRowKeys">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center">
</el-table-column>
<el-table-column prop="name" label="角色名称" align="center" width="100">
</el-table-column>
<el-table-column label="角色描述" align="center">
<template slot-scope="scope">
<el-input placeholder="该角色用于管理全部功能权限" v-model="scope.row.description" disabled></el-input>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="text" @click="showRole(scope.row)" v-auth="'system:角色权限:查看'">查看</el-button>
<el-button type="text" @click="editRole(scope.row)" v-auth="'system:角色权限:编辑'">编辑</el-button>
<!-- <el-button type="text" @click="handleDelete(scope.row)" v-auth="'system:角色权限:删除'">删除</el-button> -->
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
<el-dialog :title="isDetail ? '查看角色' : (isAdd ? '新增角色' : '编辑角色')" :visible.sync="roleVisible" width="30%" @close="closeRole" class="dialog" :close-on-click-modal="false">
<el-form ref="form" label-width="100px" :disabled="isDetail">
<el-form-item label="角色名称">
<el-input v-model="form.name " ref="account" placeholder="请输入角色名称"></el-input>
</el-form-item>
<el-form-item label="角色描述">
<el-input v-model="form.description " placeholder="请输入角色描述" type="textarea" rows="5"></el-input>
</el-form-item>
<el-form-item prop="role" label="角色权限">
<div class="per-wrap">
<el-tree
ref="per"
:data="permissions"
show-checkbox
node-key="id"
:default-expanded-keys="checkedIds"
:default-checked-keys="checkedIds"
:props="defaultProps">
</el-tree>
</div>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer" v-if="!isDetail">
<el-button size="small" @click="roleVisible = false"> </el-button>
<el-button size="small" type="primary" @click="saveData"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
keyword: '',
searchTimer: null,
isDetail: false,
form: {
roleId: '',
name: '',
description: '',
},
listData:[],
data: [{
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}]
}],
defaultProps: {
children: 'children',
label: 'name'
},
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
isAdd: true,
roleVisible: false,
permissions: [],
checkedIds: []
};
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.getData()
},500)
}
},
mounted() {
this.getData()
},
methods: {
getData() {
let data = {
name: util.encodeStr(this.keyword),
page: this.page,
size: this.pageSize
}
this.$get(this.api.rolePermissionList,data).then(res => {
this.listData = res.data.list
this.total = res.data.totalCount
}).catch(res => {});
},
currentChange(val) {
this.page = val;
this.getData();
},
handleDelete(row) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
let data = {
roleIds: [row.roleId]
}
this.$post(`${this.api.delRolePermission}`,data).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {})
},
getRowKeys(row) {
return row.roleId;
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delAllSelection() {
if(this.multipleSelection.length){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.roleId
})
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
let data = {
roleIds: delList
}
this.$post(`${this.api.delRolePermission}`,data).then(res => {
this.$refs.table.clearSelection()
util.successMsg('删除成功')
this.getData()
}).catch(res => {})
})
.catch(() => {})
}else{
util.errorMsg('请先选择数据!')
}
},
closeRole(){
this.isDetail = false
this.form = {
roleId: '',
name: '',
description: ''
}
this.checkedIds = []
this.permissions = []
},
getPer(row){
if(!this.permissions.length){
this.$get(this.api.roleTree).then(res => {
let data = res.data
let yw = data.findIndex(n => n.name == '业务后台')
yw != -1 && data.splice(yw,1)
try {
let system = data.findIndex(n => n.name == '系统设置')
if(system != -1){
data[system].children[1].children.splice(4,1)
data[system].children[1].children.splice(1,1)
data[system].children[1].children.splice(0,1)
}
} catch (error) {}
this.permissions = data
if(row){
this.getDetail(row)
}
}).catch(res => {})
}
},
addRole(){
this.isAdd = true
this.getPer()
this.checkedIds = []
this.permissions.length && this.$refs.per.setCheckedNodes([])
this.roleVisible = true
},
handleRolePer(data,permissions){
let result = data
if(permissions.length){
permissions.map(e => {
if(result.includes(e.id) && e.children){
e.children.every(n => result.includes(n)) || result.splice(result.indexOf(e.id),1)
}
e.children && e.children.length && this.handleRolePer(data,e.children)
})
}
return result
},
async getDetail(row){
let res = await this.$get(`${this.api.queryPermissionArrById}?roleId=${row.roleId}`)
if(res.success){
this.form = res.data
this.form.roleId = row.roleId
this.checkedIds = this.handleRolePer(res.data.permissionIds,this.permissions)
this.$refs.per.setCheckedNodes(this.checkedIds)
}
},
showRole(row){
this.isDetail = true
this.isAdd = false
this.getPer(row)
this.roleVisible = true
},
editRole(row){
this.isAdd = false
this.getPer(row)
this.roleVisible = true
},
async saveData() {
if(!this.form.name) return this.$message.warning('请填写角色名称')
if(!this.form.description) return this.$message.warning('请填写角色描述')
if(!this.$refs.per.getCheckedKeys().length) return this.$message.warning('请选择角色权限')
let permissionIds = [...this.$refs.per.getHalfCheckedKeys(),...this.$refs.per.getCheckedKeys()]
let data = {
roleId: this.form.roleId,
name: this.form.name,
description: this.form.description,
permissionIds
}
if(this.form.roleId){
this.$post(this.api.updateRolePermission,data).then(res => {
util.successMsg('修改成功')
this.getData()
this.roleVisible = false
}).catch(res => {})
}else{
this.$post(this.api.saveRolePermission,data).then(res => {
util.successMsg('新增成功')
this.getData()
this.roleVisible = false
}).catch(res => {})
}
},
}
};
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,864 @@
<template>
<div class="wrap">
<div class="side">
<TeacherSide ref="getSelectData" @fircheck="fircheck" @twocheck="twocheck" @getData="getData" @delDep="delDep"></TeacherSide>
</div>
<div class="right">
<div class="tool">
<ul class="filter">
<li>
<el-input size="small" placeholder="请输入员工账号/姓名/工号" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" size="small" round @click="addTeacher" v-auth="'system:员工管理:新增员工'">新增员工</el-button>
<el-button type="primary" size="small" round @click="batchImport" v-auth="'system:员工管理:批量导入'">批量导入</el-button>
<el-button type="primary" size="small" round @click="delAllSelection" v-auth="'system:员工管理:批量删除'">批量删除</el-button>
</div>
</div>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column type="index" label="序号" width="55" align="center">
</el-table-column>
<el-table-column prop="account" label="账号" align="center">
</el-table-column>
<el-table-column prop="userName" label="职工姓名" align="center">
</el-table-column>
<el-table-column prop="workNumber" label="职工工号" align="center">
</el-table-column>
<el-table-column prop="staffProfessionalArchitectureName" label="一级部门" align="center">
</el-table-column>
<el-table-column prop="staffGradeName" label="二级部门" align="center">
</el-table-column>
<el-table-column prop="NewaccountRole" label="账号角色" align="center">
</el-table-column>
<el-table-column prop="logInNumber" label="登录次数" align="center">
</el-table-column>
<el-table-column prop="lastLoginTime" label="上次登录时间" align="center">
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="text" @click="showTeacher(scope.row)" v-auth="'system:员工管理:查看'">查看</el-button>
<el-button type="text" @click="editTeacher(scope.row)" v-auth="'system:员工管理:编辑'">编辑</el-button>
<el-button type="text" @click="resetPassword(scope.row)" v-auth="'system:员工管理:重置密码'">重置密码</el-button>
<el-button type="text" @click="delTeacher(scope.row)" v-auth="'system:员工管理:删除'">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :current-page="page" @current-change="handleCurrentChange" :total="total"></el-pagination>
</div>
</div>
<el-dialog :title="isDetail ? '查看员工' : (isAddteacher ? '新增员工' : '编辑员工')" :visible.sync="teacherVisible" width="30%" @close="closeTeacher" class="dialog" :close-on-click-modal="false">
<el-form ref="teacherForm" :model="teacherForm" :rules="rules" label-width="120px" :disabled="isDetail">
<el-form-item prop="userAccount" label="账号">
<el-input v-model="teacherForm.userAccount" ref="account" placeholder="请输入职工账号" @change="accountChange"></el-input>
</el-form-item>
<el-form-item prop="userName" label="用户姓名">
<el-input v-model="teacherForm.userName" placeholder="请输入员工姓名"></el-input>
</el-form-item>
<el-form-item prop="roleValue" label="账号角色">
<el-checkbox-group v-model="teacherForm.roleValue">
<el-checkbox label="老师"></el-checkbox>
<el-checkbox label="管理员"></el-checkbox>
<!-- <el-checkbox label="学生" disabled></el-checkbox> -->
</el-checkbox-group>
</el-form-item>
<el-form-item prop="uniqueIdentificationAccount" label="唯一标识">
<el-input disabled v-model="teacherForm.uniqueIdentificationAccount" placeholder="请输入职工工号获取唯一标识"></el-input>
</el-form-item>
<template v-if="teacherForm.roleValue.some((n) => n == '老师')">
<el-form-item prop="teacherWorkNumber" label="老师职工工号">
<el-input v-model="teacherForm.teacherWorkNumber" placeholder="请输入老师职工工号" @change="OnlyId(14)"></el-input>
</el-form-item>
<el-form-item prop="teacherMajor" label="老师一级部门">
<el-select v-model="teacherForm.teacherMajor" placeholder="请选择一级部门" @change="getDepartment(14)">
<el-option v-for="(item,index) in majorList" :key="index"
:label="item.staffProfessionalArchitectureName" :value="item.staffProfessionalArchitectureId"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="teacherDepartment" label="老师二级部门">
<el-select v-model="teacherForm.teacherDepartment" placeholder="请选择二级部门" :disabled="teacherForm.teacherMajor ? false : true">
<el-option v-for="(item,index) in teacherDepartmentList" :key="index"
:label="item.staffGradeName" :value="item.staffGradeId"></el-option>
</el-select>
</el-form-item>
</template>
<template v-if="teacherForm.roleValue.some((n) => n == '管理员')">
<el-form-item prop="managerWorkNumber" label="管理员职工工号">
<el-input v-model="teacherForm.managerWorkNumber" placeholder="请输入管理员职工工号" @change="OnlyId(13)"></el-input>
</el-form-item>
<el-form-item prop="managerMajor" label="管理员一级部门">
<el-select v-model="teacherForm.managerMajor" placeholder="请选择一级部门" @change="getDepartment(13)">
<el-option v-for="(item,index) in majorList" :key="index"
:label="item.staffProfessionalArchitectureName" :value="item.staffProfessionalArchitectureId"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="managerDepartment" label="管理员二级部门">
<el-select v-model="teacherForm.managerDepartment" placeholder="请选择二级部门" :disabled="teacherForm.managerMajor ? false : true">
<el-option v-for="(item,index) in managerDepartmentList" :key="index"
:label="item.staffGradeName" :value="item.staffGradeId"></el-option>
</el-select>
</el-form-item>
</template>
<el-form-item prop="phone" label="手机号">
<el-input v-model="teacherForm.phone" placeholder="请输入手机号" maxlength="11" @change="phoneChange"></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model="teacherForm.email" placeholder="请输入邮箱" @change="emailChange"></el-input>
</el-form-item>
<el-form-item prop="schoolId" label="所在院校">
<el-select v-model="teacherForm.schoolId" placeholder="默认为当前院校(可修改)" filterable disabled>
<el-option v-for="(item,index) in schoolList" :key="index" :label="item.schoolName" :value="item.schoolId"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer" v-if="!isDetail">
<el-button size="small" @click="teacherVisible = false"> </el-button>
<el-button size="small" type="primary" @click="saveSure('teacherForm')"> </el-button>
</span>
</el-dialog>
<el-dialog title="批量导入" :visible.sync="importVisible" width="24%" :close-on-click-modal="false">
<div style="text-align: center">
<div style="margin-bottom: 10px;"><el-button type="primary" @click="downLoad">模板下载<i class="el-icon-download el-icon--right"></i></el-button></div>
<el-upload
accept=".xls,.xlsx"
:on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:action="this.api.uploadFileStaff"
:file-list="uploadList"
name="file"
>
<el-button type="primary" class="ml20">上传文件<i class="el-icon-upload2 el-icon--right"></i></el-button>
</el-upload>
<el-link v-if="uploadFaild" type="primary" @click="showFaild">部分数据导入失败查看失败原因</el-link>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="importVisible = false"> </el-button>
<el-button size="small" type="primary" @click="uploadSure"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import { mapState, mapActions } from 'vuex'
import TeacherSide from './staffSide'
export default {
data() {
return {
isDetail: false,
isAddteacher: false,
teacherVisible: false,
schoolId: Setting.schoolId,
teacherForm: {
teacherId: '',
userName: '',
roleValue: [],
tearcherAccount: '',
phone: '',
uniqueIdentificationAccount: '',
teacherWorkNumber: '',
managerWorkNumber: '',
email: '',
teacherMajor: '',
teacherDepartment: '',
managerMajor: '',
managerDepartment: '',
userAccount: '',
major: '',
schoolId: Setting.schoolId
},
rules: {
userAccount: [
{ required: true, message: '请输入职工账号', trigger: 'blur' },
{
pattern: /^[A-Za-z0-9]*$/,
message: '请输入正确的账号',
trigger: 'blur'
}
],
userName: [
{ required: true, message: '请输入用户姓名', trigger: 'blur' }
],
roleValue: [
{ required: true, message: '请选择账号角色', trigger: 'change' }
],
tearcherAccount: [
{ required: true, message: '请输入老师职工工号', trigger: 'blur' },
{
pattern: /^[0-9]*$/,
message: '职工工号必须为数字',
trigger: 'blur'
}
],
uniqueIdentificationAccount: [
// { required: true, message: '', trigger: 'blur' },
],
teacherWorkNumber: [
{ required: true, message: '请输入老师职工工号', trigger: 'blur' },
{
pattern: /^[A-Za-z0-9]+$/,
message: '请输入正确的职工工号',
trigger: 'blur'
}
],
teacherDepartment: [
{ required: true, message: '请选择老师二级部门', trigger: 'change' }
],
managerMajor: [
{ required: true, message: '请选择管理员一级部门', trigger: 'change' }
],
managerWorkNumber: [
{ required: true, message: '请输入管理员职工工号', trigger: 'blur' },
{
pattern: /^[A-Za-z0-9]+$/,
message: '请输入正确的职工工号',
trigger: 'blur'
}
],
managerDepartment: [
{ required: true, message: '请选择管理员二级部门', trigger: 'change' }
],
teacherMajor: [
{ required: true, message: '请选择老师一级部门', trigger: 'change' }
],
phone: [
// { required: true, message: '', trigger: 'blur' },
{
pattern: /^1[3456789]\d{9}$/,
message: '请输入正确的手机号',
trigger: 'blur'
}
],
email: [
// { required: true, message: '', trigger: 'blur' },
{
pattern: /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/,
message: '请输入正确的邮箱',
trigger: 'blur'
}
],
schoolId: [
{ required: true, message: '请选择所在院校', trigger: 'change' }
],
},
listData: [],
importVisible: false,
keyword: '',
page: 1,
pageSize: 10,
total: 0,
managerDepartmentList: [],
teacherDepartmentList: [],
staffstateProfessId: '',
staffGradeId: '',
multipleSelection: [],
uploadList: [],
provinceId: this.$store.state.provinceId,
cityId: this.$store.state.cityId,
userId: this.$store.state.userId,
oneDepartmentIds: '',
twoDepartmentIds: '',
ProfessionalClassList: [],
subjectList: [],
ProfessionalList: [],
NoAdd: '',
AccountNoAdd: '',
emailNoAdd: '',
managerNumberNoAdd: true,
teacherNumberNoAdd: true,
platformId: this.$store.state.platformId,
isManager: false,
isTeacher: false,
isNewUser: 1,
schoolList: [],
uploadFaild: false,
token: '',
accountMsg: ''
};
},
components: {
TeacherSide
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.getData()
},500)
}
},
mounted(){
this.getData()
this.teacherForm.schoolId = Setting.schoolId
console.log(33,this.schoolId,this.teacherForm.schoolId)
this.getSchoolData()
},
methods: {
handleCheck(data){
let oneDepartmentIds = []
let twoDepartmentIds = []
data.forEach( e => {
if(e.ischeck){
oneDepartmentIds.push(e.staffProfessionalArchitectureId)
}else{
this.removeByValue(oneDepartmentIds, e.staffProfessionalArchitectureId);
}
e.children.forEach( r => {
if(r.ischeck){
twoDepartmentIds.push(r.staffGradeId)
}else{
this.removeByValue(twoDepartmentIds, r.staffGradeId);
}
})
})
this.oneDepartmentIds = oneDepartmentIds.toString()
this.twoDepartmentIds = twoDepartmentIds.toString()
this.getData()
},
fircheck(val,val2){
val.ischeck = !val.ischeck
val.children.map( e => e.ischeck = val.ischeck)
this.handleCheck(val2)
},
twocheck(val,val2){
val.ischeck = !val.ischeck
val2.map( e => {
e.children.map( r => {
if(r.staffGradeId == val.staffGradeId){
if(e.children.every(i => i.ischeck)){
e.ischeck = true
}else{
e.ischeck = false
}
}
})
})
this.handleCheck(val2)
},
delDep(val,val2){
this.handleCheck(val2)
},
getData(){
let data = {
staffProfessionalArchitectureIds: (this.oneDepartmentIds && this.twoDepartmentIds) ? '' : this.oneDepartmentIds,
staffGradeIds: this.twoDepartmentIds,
searchContent: util.encodeStr(this.keyword),
page: this.page,
size: this.pageSize,
schoolId: this.schoolId
}
this.$post(this.api.queryStaff,data).then(res => {
this.listData = res.data.list
this.total = res.data.totalCount
this.listData.forEach(e => {
if(e.roleId.length > 1) {
let NewaccountRole = []
let roleIds = e.roleId.split(',')
roleIds.forEach((n,k) => {
NewaccountRole.push(util.getRoleName(n))
})
e.NewaccountRole = NewaccountRole.join(',')
}else{
e.NewaccountRole = util.getRoleName(e.roleId)
}
})
}).catch(res => {});
},
getSchoolData(){
let data = {
schoolName: '',
provinceId: '',
cityId: ''
}
this.$get(this.api.querySchool,data).then(res => {
this.schoolList = res.message
}).catch(res => {});
},
closeTeacher(){
this.teacherForm= {
teacherId: '',
userName: '',
roleValue: [],
tearcherAccount: '',
phone: '',
uniqueIdentificationAccount: '',
teacherWorkNumber: '',
managerWorkNumber: '',
email: '',
teacherMajor: '',
teacherDepartment: '',
managerMajor: '',
managerDepartment: '',
userAccount: '',
major: '',
schoolId: this.schoolId
}
this.isManager = false
this.isTeacher = false
this.$refs.teacherForm.clearValidate()
},
addTeacher(){
this.isDetail = false
this.teacherVisible = true
this.isAddteacher = true
this.teacherForm.teacherId = ''
this.majorList = this.$refs.getSelectData.majorList
this.$refs.teacherForm.clearValidate()
},
getStaffDetail(userId){
let data = {
userId: userId
}
this.$get(this.api.querystaffDetail,data).then(res => {
let user = res.data.userInfo;
let or = res.data.staffInfo;
this.teacherForm.userName = user.userName
this.teacherForm.phone = user.phone
this.teacherForm.email = user.email
this.teacherForm.userAccount = user.account
this.teacherForm.userId = user.userId
this.teacherForm.schoolId = user.schoolId
this.teacherForm.uniqueIdentificationAccount = user.uniqueIdentificationAccount
or.forEach((n,i) => {
this.teacherForm.roleValue.push(util.getRoleName(n.roleId))
if(n.roleId == 13) {
this.teacherForm.managerMajor = n.staffProfessionalArchitectureId
this.teacherForm.managerDepartment = n.staffGradeId
this.teacherForm.managerWorkNumber = n.workNumber
this.isManager = true
this.teacherForm.managerStaffId = n.staffId
this.getDepartment(13)
}else if(n.roleId == 14){
this.teacherForm.teacherMajor = n.staffProfessionalArchitectureId
this.teacherForm.teacherDepartment = n.staffGradeId
this.teacherForm.teacherWorkNumber = n.workNumber
this.isTeacher = true
this.teacherForm.teacherStaffId = n.staffId
this.getDepartment(14)
}
})
}).catch(res => {});
},
editTeacher(row){
this.isDetail = false
this.teacherVisible = true
this.isAddteacher = false
this.AccountNoAdd = false
this.teacherForm.teacherId = row.userId
this.majorList = this.$refs.getSelectData.majorList
this.isNewUser = 0
this.getStaffDetail(row.userId)
},
resetPassword(row){
this.$confirm(`重置后的密码为:${this.$config.initialPassword},确定重置?`, '提示', {
}).then(() => {
let data = {
newPwd: this.$config.initialPassword,
userId: row.userId,
}
this.$get(this.api.resetPwd,data).then(res => {
if(res.errmessage == 'success'){
util.successMsg('重置成功')
}else{
util.errorMsg('重置失败')
}
}).catch(res => {});
}).catch(() => {
});
},
showTeacher(row){
this.isDetail = true
this.teacherVisible = true
this.isAddteacher = false
this.AccountNoAdd = false
this.teacherForm.teacherId = row.userId
this.majorList = this.$refs.getSelectData.majorList
this.isNewUser = 0
this.getStaffDetail(row.userId)
},
getDepartment(type){
let data = {
staffProfessionalArchitectureId: type == 13 ? this.teacherForm.managerMajor : this.teacherForm.teacherMajor
}
this.$get(this.api.queryStaffGrade,data).then(res => {
if(type == 13){
this.managerDepartmentList = res.message
}else{
this.teacherDepartmentList = res.message
}
}).catch(res => {});
},
async phoneChange(){
let res = await this.$get(this.api.queryPhone, { phone: this.teacherForm.phone });
if(res.message.length != 0){
this.$message.warning('该手机号已存在');
this.NoAdd = false
}else{
this.NoAdd = true
}
},
async emailChange(){
let res = await this.$get(this.api.queryEmail, { email: this.teacherForm.email });
if(res.message.length != 0){
this.$message.warning('该邮箱已存在');
this.emailNoAdd = false
}else{
this.emailNoAdd = true
}
},
async accountChange(){
let res = await this.$get(this.api.queryAccountIsExist, {
account: util.encodeStr(this.teacherForm.userAccount),
schoolId: this.schoolId
});
if(this.isAddteacher){
this.isManager = false
this.isTeacher = false
}
if(res.message.user.length != 0){
let user = res.message.user[0];
let or = res.message.OR;
if(user.roleId){
this.accountMsg = user.roleId.includes(',') ? '该账号已绑定老师和管理员' : `该账号已绑定${util.getRoleName(user.roleId)}`
}else{
this.accountMsg = '该账号已存在'
}
this.$message.warning(this.accountMsg)
this.teacherForm.email = user.email
this.teacherForm.phone = user.phone
this.teacherForm.uniqueIdentificationAccount = user.uniqueIdentificationAccount
this.teacherForm.userName = user.userName
// this.teacherForm.schoolId = user.schoolId
this.teacherForm.userId = user.userId
this.isNewUser = 0
or.forEach((n,i) => {
this.teacherForm.roleValue.push(util.getRoleName(n.roleId))
if(n.roleId == 13) {
this.teacherForm.managerMajor = n.oneDepartmentId
this.teacherForm.managerDepartment = n.twoDepartmentId
this.teacherForm.managerWorkNumber = n.workNumber
this.teacherForm.managerSchoolId = n.schoolId
this.teacherForm.managerSchoolName = n.schoolName
this.isManager = true
this.getDepartment(13)
}else if(n.roleId == 14){
this.teacherForm.teacherMajor = n.oneDepartmentId
this.teacherForm.teacherDepartment = n.twoDepartmentId
this.teacherForm.teacherWorkNumber = n.workNumber
this.teacherForm.teacherSchoolId = n.schoolId
this.teacherForm.tacherSchoolName = n.schoolName
this.isTeacher = true
this.getDepartment(14)
}
})
this.AccountNoAdd = false
}else{
this.isNewUser = 1
this.AccountNoAdd = true
this.teacherForm.userName = ''
}
},
async submitOnlyId(){
if(this.teacherForm.managerWorkNumber != ''){
this.OnlyId(13)
}else if(this.teacherForm.teacherWorkNumber != ''){
this.OnlyId(14)
}
},
async OnlyId(type){
let data = {};
let msg = '';
if(type == 13){
data = {
workNumber: util.encodeStr(this.teacherForm.managerWorkNumber),
roleId: 13,
schoolId: this.teacherForm.schoolId
}
msg = '该管理员工号已存在'
}else if(type == 14){
data = {
workNumber: util.encodeStr(this.teacherForm.teacherWorkNumber),
roleId: 14,
schoolId: this.teacherForm.schoolId
}
msg = '该老师工号已存在'
}
let res = await this.$get(this.api.queryWorkNumberIsExist, data);
if(JSON.stringify(res.message) != '{}'){
this.$message.warning(msg);
type == 13 ? (this.managerNumberNoAdd = false) : (this.teacherNumberNoAdd = false)
}else{
let timestamp = Date.parse(new Date());
this.teacherForm.uniqueIdentificationAccount = `${this.schoolId}${this.teacherForm.uniqueIdentificationAccount}${timestamp}`
type == 13 ? (this.managerNumberNoAdd = true) : (this.teacherNumberNoAdd = true)
}
},
async saveSure(teacherForm){
this.$refs[teacherForm].validate((valid) => {
if (valid) {
if(this.isAddteacher) {
if(this.isManager && this.isTeacher) return this.$message.warning('该用户已经是老师和管理员,请重新添加');
if(this.isManager && !this.teacherForm.roleValue.some((n) => n == '老师')) return this.$message.warning('该用户已经是管理员');
if(this.isTeacher && !this.teacherForm.roleValue.some((n) => n == '管理员')) return this.$message.warning('该用户已经是老师');
if(!this.AccountNoAdd) return this.$message.warning(this.accountMsg)
if(this.NoAdd == '' && this.teacherForm.phone){
this.phoneChange()
if(!this.NoAdd) return false
}else if(this.NoAdd === false){
return this.$message.warning('该手机号已存在')
}else if(this.emailNoAdd === false){
return this.$message.warning('该邮箱已存在')
}
}
if(!this.managerNumberNoAdd) return this.$message.warning('该管理员工号已存在');
if(!this.teacherNumberNoAdd) return this.$message.warning('该老师工号已存在');
let roleId = []
this.teacherForm.roleValue.includes('管理员') && roleId.push(13)
this.teacherForm.roleValue.includes('老师') && roleId.push(14)
let data = {
userName: this.teacherForm.userName,
account: this.teacherForm.userAccount,
schoolId: this.teacherForm.schoolId,
roleId: roleId.join(','),
phone: this.teacherForm.phone,
email: this.teacherForm.email,
uniqueIdentificationAccount: this.teacherForm.uniqueIdentificationAccount ? this.teacherForm.uniqueIdentificationAccount : Date.parse(new Date()),
userId: this.teacherForm.userId ? this.teacherForm.userId : ''
}
data.staff = [];
if((!this.isAddteacher && this.teacherForm.managerWorkNumber && roleId.includes(13)) || (this.isAddteacher && !this.isManager && this.teacherForm.managerWorkNumber)){
let oneDepartmentName = '';
for(let i in this.majorList){
if(this.majorList[i].staffProfessionalArchitectureId == this.teacherForm.managerMajor) {
oneDepartmentName = this.majorList[i].staffProfessionalArchitectureName
break;
}
}
let twoDepartmentName = this.managerDepartmentList.find((n) => {
return n.staffGradeId == this.teacherForm.managerDepartment
}).staffGradeName;
let orList = {
roleId: 13,
staffId: this.teacherForm.managerStaffId,
workNumber: this.teacherForm.managerWorkNumber,
staffProfessionalArchitectureId: this.teacherForm.managerMajor,
staffGradeId: this.teacherForm.managerDepartment,
staffProfessionalArchitectureName: oneDepartmentName,
staffGradeName: twoDepartmentName,
};
data.staff.push(orList)
}
if((!this.isAddteacher && this.teacherForm.teacherWorkNumber && roleId.includes(14)) || (this.isAddteacher && !this.isTeacher && this.teacherForm.teacherWorkNumber)){
let oneDepartmentName = '';
for(let i in this.majorList){
if(this.majorList[i].staffProfessionalArchitectureId == this.teacherForm.teacherMajor) {
oneDepartmentName = this.majorList[i].staffProfessionalArchitectureName
break;
}
}
let twoDepartmentName = this.teacherDepartmentList.find((n) => {
return n.staffGradeId == this.teacherForm.teacherDepartment
}).staffGradeName;
let orList = {
roleId: 14,
staffId: this.teacherForm.teacherStaffId,
workNumber: this.teacherForm.teacherWorkNumber,
staffProfessionalArchitectureId: this.teacherForm.teacherMajor,
staffGradeId: this.teacherForm.teacherDepartment,
staffProfessionalArchitectureName: oneDepartmentName,
staffGradeName: twoDepartmentName,
};
data.staff.push(orList)
}
if(this.teacherForm.teacherId){
this.$put(this.api.updateStaff,data).then(res => {
this.teacherVisible = false
util.successMsg('编辑成功');
this.getData()
}).catch(res => {});
}else{
this.$post(this.api.addStaff,data).then(res => {
this.teacherVisible = false
util.successMsg('添加成功');
this.getData()
}).catch(res => {});
}
}else{
return false;
}
})
},
delTeacher(row){
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(this.api.daleteBatchStaff,[row.userId]).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delAllSelection() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.userId
})
//
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
})
.then(() => {
let data = delList
this.$post(this.api.daleteBatchStaff,data).then(res => {
this.$refs.table.clearSelection()
this.multipleSelection = [];
util.successMsg('删除成功')
this.getData()
}).catch(res => {});
}).catch(() => {});
}else{
util.errorMsg('请先选择员工 !')
}
},
batchImport(){
this.importVisible = true
this.uploadList = []
this.uploadFaild = false
},
searchTeacher(){
this.page = 1;
this.getData()
},
handleCurrentChange(val) {
this.page = val;
this.getData();
},
downLoad(){
location.href = this.api.staffTemplate
},
showFaild(){
location.href = `${this.api.export_failureStaff}?token=${this.token}`
},
//
handleExceed(files, fileList) {
this.$message.warning(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
this.uploadFaild = false
if(res.errmessage == 'success'){
if(res.data.token){
this.token = res.data.token
this.uploadFaild = true
}else{
util.successMsg('上传成功')
}
}else{
res.message ? util.errorMsg(res.message) : util.errorMsg('上传失败,请检查数据')
}
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
this.uploadList = fileList
this.uploadFaild = false
},
uploadSure(){
this.importVisible = false
this.page = 1
this.keyword = ''
this.getData()
},
//
getSubject(){
this.$get(this.api.queryCourseDiscipline).then(res => {
this.subjectList = res.message
}).catch(res => {});
},
//
clearClass(){
this.teacherForm.professionalClassId = '',
this.teacherForm.professionalId = ''
},
//
getProfessionalClass(){
this.clearClass()
if(this.teacherForm.disciplineId){
this.getProfessionalClassData()
}
},
getProfessionalClassData(){
let data = {
disciplineId: this.teacherForm.disciplineId
}
this.$get(this.api.queryCourseProfessionalClass,data).then(res => {
this.ProfessionalClassList = res.message
}).catch(res => {});
},
//
clearProfess(){
this.teacherForm.professionalId = ''
},
//
getProfessional(){
this.clearProfess()
if(this.teacherForm.professionalClassId){
this.getProfessionalData()
}
},
getProfessionalData(){
let data = {
professionalClassId: this.teacherForm.professionalClassId
}
this.$get(this.api.queryCourseProfessional,data).then(res => {
this.ProfessionalList = res.message
}).catch(res => {});
}
}
};
</script>
<style lang="scss" scoped>
.wrap{
display: flex;
padding: 24px;
.side{
width: 350px;
margin-right: 24px;
}
.right{
width: calc(100% - 374px);
padding: 24px;
}
}
</style>

@ -0,0 +1,363 @@
<template>
<div>
<div>
<lctree :data="majorList"
@addMajor="addMajor" @editMajor="editMajor" @delMajor="delMajor"
@addDepartment="addDepartment" @editDepartment="editDepartment" @delDepartment="delDepartment"
@fircheckitem="fircheckitem" @twocheckitem="twocheckitem"
></lctree>
</div>
<el-dialog :title="Form.MajorId ? '编辑专业' : '新增专业'" :visible.sync="isaddMajor" width="24%" center @close="closeAdd" :close-on-click-modal="false">
<el-form ref="Form" :model="Form" :rules="rules">
<el-form-item prop="majorName">
<el-input placeholder="请输入专业名称" v-model="Form.majorName" @change="majorChange"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="isaddMajor = false"> </el-button>
<el-button type="primary" @click="sure('Form')"> </el-button>
</span>
</el-dialog>
<el-dialog :title="Form.departmentId ? '编辑部门' : '新增部门'" :visible.sync="isAddDepartment" width="24%" center @close="closeAdd" :close-on-click-modal="false">
<el-form ref="Form" :model="Form" :rules="rules">
<el-form-item prop="departmentName">
<el-input placeholder="请输入部门名称" v-model="Form.departmentName"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="isAddDepartment = false"> </el-button>
<el-button type="primary" @click="sureDepartment('Form')"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from '@/setting'
import util from '@/libs/util'
import { mapState, mapActions } from 'vuex'
import lctree from './stafftree'
export default {
props:["Data"],
data() {
return {
majorList: [],
firactive: 0,
twoactive: 0,
isaddMajor: false,
isAddDepartment: false,
schoolId: Setting.schoolId,
Form: {
MajorId: '',
majorName: '',
departmentId: '',
departmentName: ''
},
rules: {
majorName: [
{ required: true, message: '请输入专业名称', trigger: 'blur' }
],
departmentName: [
{ required: true, message: '请输入部门名称', trigger: 'blur' }
]
},
staffstateProfessId: '',
staffstateId: '',
majorNoAdd: true
};
},
components: {
lctree
},
mounted(){
this.getStaff()
},
methods: {
getStaff(){
let data = {
schoolId: this.schoolId
}
this.$get(this.api.queryStaffPro,data).then(res => {
if(res.message){
res.message.map(e => {
(e.ifVisible = false), (e.ischeck = false), (e.label = e.staffProfessionalArchitectureName);
let data = {
staffProfessionalArchitectureId: e.staffProfessionalArchitectureId
}
this.$get(this.api.queryStaffGrade,data).then(res => {
res.message.map(e => {
(e.ischeck = false), (e.label = e.staffGradeName);
})
e.children = res.message
}).catch(res => {});
})
}
setTimeout(() => {
this.majorList = res.message
}, 500);
}).catch(res => {});
},
//
fircheckitem(item){
this.$emit("fircheck",item,this.majorList)
},
//
twocheckitem(item){
this.$emit("twocheck",item,this.majorList)
},
closeAdd(){
this.$refs.Form.resetFields()
},
//
addMajor(){
this.Form.MajorId = ''
this.Form.majorName = ''
this.isaddMajor = true
},
editMajor(item){
this.Form.MajorId = item.staffProfessionalArchitectureId,
this.Form.majorName = item.staffProfessionalArchitectureName
this.isaddMajor = true
},
async majorChange(){
let res = await this.$get(this.api.queryStaffPAN, { name: this.Form.majorName,schoolId: this.schoolId });
if(res.message.length != 0){
this.$message.warning('该一级部门已存在');
this.majorNoAdd = false
}else{
this.majorNoAdd = true
}
},
sure(Form){
this.$refs[Form].validate((valid) => {
if (valid) {
if(!this.majorNoAdd) return this.$message.warning('该一级部门已存在');
let data = {
staffProfessionalArchitectureName: this.Form.majorName,
staffProfessionalArchitectureId: this.Form.MajorId,
schoolId: this.schoolId,
}
if(this.Form.MajorId){
this.$post(this.api.updateStaffPro,data).then(res => {
util.successMsg('编辑成功');
this.isaddMajor = false
this.majorList.map(e =>{
if(e.staffProfessionalArchitectureId == this.Form.MajorId){
e.staffProfessionalArchitectureName = this.Form.majorName
e.label = this.Form.majorName
}
})
this.$emit('getData')
}).catch(res => {});
}else{
this.$post(this.api.addStaffPro,data).then(res => {
util.successMsg('添加成功');
this.isaddMajor = false
let newData = {
staffProfessionalArchitectureId: res.message,
staffProfessionalArchitectureName: this.Form.majorName,
label: this.Form.majorName,
ifVisible: false,
ischeck: false,
children: []
}
this.majorList.push(newData)
}).catch(res => {});
}
}else{
return false;
}
})
},
//
addDepartment(item){
this.Form.departmentId = ''
this.Form.departmentName = ''
this.isAddDepartment = true
this.Form.MajorId = item.staffProfessionalArchitectureId
},
editDepartment(item){
this.Form.departmentId = item.staffGradeId,
this.Form.departmentName = item.staffGradeName
this.isAddDepartment = true
for (let j = 0; j < this.majorList.length; j++) {
for (let k = 0; k < this.majorList[j].children.length; k++) {
if(this.majorList[j].children[k].staffGradeName == item.staffGradeName){
this.Form.MajorId = this.majorList[j].staffProfessionalArchitectureId
}
}
}
},
sureDepartment(Form){
this.$refs[Form].validate((valid) => {
if (valid) {
let data = {
staffGradeName: this.Form.departmentName,
staffProfessionalArchitectureId: this.Form.MajorId,
staffGradeId: this.Form.departmentId
}
if(this.Form.departmentId){
this.$post(this.api.updateStaffGrade,data).then(res => {
util.successMsg('编辑成功');
this.isAddDepartment = false
this.majorList.map(e =>{
e.children.map(r =>{
if(r.staffGradeId == this.Form.departmentId){
r.staffGradeName = this.Form.departmentName
r.label = this.Form.departmentName
}
})
})
}).catch(res => {});
}else{
this.$post(this.api.addStaffGrade,data).then(res => {
util.successMsg('添加成功');
this.isAddDepartment = false
let newData = {
staffGradeId: res.message,
staffGradeName: this.Form.departmentName,
label: this.Form.departmentName,
ifVisible: false,
ischeck: false
}
this.majorList.map(e =>{
if(e.staffProfessionalArchitectureId == this.Form.MajorId){
e.ifVisible = true
e.children.push(newData)
}
})
}).catch(res => {});
}
}else{
return false;
}
})
},
delMajor(item,index){
this.$confirm('确定要删除该专业吗?该操作将会删除该组织下的用户账号。', '提示', {
type: 'warning'
})
.then(() => {
let data = {
staffProfessionalArchitectureId: item.staffProfessionalArchitectureId
}
this.$post(this.api.deleteStaffPro,data).then(res => {
util.successMsg('删除成功');
this.majorList.splice(index, 1)
this.$emit('getData')
this.$get(`${this.api.dalStaffByProfessionalId}?staffProfessionalArchitectureId=${item.staffProfessionalArchitectureId}`).then(res => {}).catch(res => {})
}).catch(res => {});
})
.catch(() => {});
},
delDepartment(item,indx){
this.$confirm('确定要删除该部门吗?该操作将会删除该组织下的用户账号。', '提示', {
type: 'warning'
})
.then(() => {
let data = {
staffGradeId: item.staffGradeId
}
this.$post(this.api.deleteStaffGrade,data).then(res => {
util.successMsg('删除成功');
this.majorList.map(e =>{
e.children.map(r =>{
if(r.staffGradeId == item.staffGradeId){
e.children.splice(indx,1)
if(e.children.length == 0){
e.ifVisible = false
}
}
})
})
this.$emit("delDep",item,this.majorList)
this.$emit('getData')
this.$get(`${this.api.dalStaffByStaffGradeId}?staffGradeId=${item.staffGradeId}`).then(res => {}).catch(res => {})
}).catch(res => {});
})
.catch(() => {});
}
}
};
</script>
<style scoped>
.side_view{
height: 800px;
padding: 40px 20px;
background-color: #fff;
box-shadow:-2px 0px 57px 0px rgba(192,189,216,0.39);
}
.side_icon{
text-align: right;
}
.side_icon i{
cursor:pointer;
font-size: 20px;
color: #9278FF;
}
.side_tree{
width: 100%;
font-size: 14px;
color: #333;
}
.side_tree i{
color: #9278FF;
margin-left: 10px;
}
.fir_back{
width: 100%;
padding: 15px 0;
background:rgba(255,255,255,1);
/* box-shadow:1px 14px 29px 0px rgba(138,97,250,0.19); */
border-radius:10px;
text-align: left;
}
.fir_back:first-child{
margin-top: 20px;
}
.fir_back:hover{
box-shadow:1px 14px 29px 0px rgba(138,97,250,0.19);
cursor:pointer;
}
.fir_back span{
margin-left: 10px;
}
.two_active{
color: #9278FF;
}
/* .two_active:hover{
color: #9278FF;
cursor:pointer;
} */
.two_back:hover{
cursor:pointer;
color: #9278FF;
}
.mar_top{
margin-top: 20px;
}
.back_active{
box-shadow:1px 14px 29px 0px rgba(138,97,250,0.19);
}
.bor_lef{
padding: 20px 0 0 0;
margin-left: 40px;
}
.three_lef{
margin-left: 60px;
padding: 20px 0;
}
.three_text{
font-size: 14px;
margin-top: 10px;
}
.teacher_tab{
margin-left: 20px;
}
.icon_select:before{
transform: rotate(180deg);
}
.list-enter-active, .list-leave-active { transition: all 1s; }
.list-enter, .list-leave-to { opacity: 0; transform: translateY(-30px); }
</style>

@ -0,0 +1,251 @@
<template>
<div class="side_view">
<p class="side_icon mab20">
<i class="icon-jiahao mar20" @click="addMajor"></i>
</p>
<div class="side_tree" v-for="(item,index) in data" :key="index">
<div class="item" @click.stop="open(item,1)">
<img
v-if="item.children&&item.children.length!=0"
:class="{ 'arrowTransform': !item.ifVisible, 'arrowTransformReturn': item.ifVisible}"
src="@/assets/img/icon-xiangyou.png"
alt
/>
<i v-else class="empty"></i>
<i :class="item.ischeck ? 'icon-yigouxuan' : 'icon-weigouxuan'" @click.stop="fircheckitem(item)"></i>
<span>{{item.label}}</span>
<svg t="1604370117041" class="icon edit ft" @click.stop="editMajor(item)" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9029" width="16" height="16"><path d="M511.979 30.125c-266.13 0-481.871 215.741-481.871 481.871s215.741 481.871 481.871 481.871S993.85 778.126 993.85 511.996 778.109 30.125 511.979 30.125zM459.644 693.015c-15.876 18.135-22.818 22.486-44.972 30.657-34.111 12.787-96.687 36.27-137.374 51.515-7.706 3.056-36.735 1.495-24.578-27.036 13.784-39.757 34.045-98.414 45.636-131.894 8.436-23.615 11.758-29.76 28.73-45.603l175.271-175.271 124.055 124.088C626.413 519.471 508.469 642.264 459.644 693.015zM653.084 492.867 528.996 368.779l26.605-26.605 124.088 124.121L653.084 492.867zM759.469 386.482l-53.176 53.209L582.205 315.569l53.209-53.176c19.596-19.596 51.316-19.596 70.912 0l53.209 53.176C779.065 335.166 779.065 366.919 759.469 386.482z" p-id="9030" fill="#9076ff"></path></svg>
<i class="el-icon-circle-plus ft fz" @click.stop="addDepartment(item)"></i>
<i class="icon-delete ft" @click.stop="delMajor(item,index)"></i>
</div>
<div v-show="item.ifVisible" v-if="item.children&&item.children.length!=0">
<div v-for="(item1,index1) in item.children" :key="index1">
<div class="item2" @click.stop="open(item1,2)">
<i :class="item1.ischeck ? 'icon-yigouxuan' : 'icon-weigouxuan'" @click.stop="twocheckitem(item1)"></i>
<span>{{item1.label}}</span>
<svg t="1604370117041" class="icon edit ft" @click.stop="editDepartment(item1)" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9029" width="16" height="16"><path d="M511.979 30.125c-266.13 0-481.871 215.741-481.871 481.871s215.741 481.871 481.871 481.871S993.85 778.126 993.85 511.996 778.109 30.125 511.979 30.125zM459.644 693.015c-15.876 18.135-22.818 22.486-44.972 30.657-34.111 12.787-96.687 36.27-137.374 51.515-7.706 3.056-36.735 1.495-24.578-27.036 13.784-39.757 34.045-98.414 45.636-131.894 8.436-23.615 11.758-29.76 28.73-45.603l175.271-175.271 124.055 124.088C626.413 519.471 508.469 642.264 459.644 693.015zM653.084 492.867 528.996 368.779l26.605-26.605 124.088 124.121L653.084 492.867zM759.469 386.482l-53.176 53.209L582.205 315.569l53.209-53.176c19.596-19.596 51.316-19.596 70.912 0l53.209 53.176C779.065 335.166 779.065 366.919 759.469 386.482z" p-id="9030" fill="#9076ff"></path></svg>
<i class="icon-delete ft" @click.stop="delDepartment(item1,index1)"></i>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
Array.prototype.removeByValue = function (val) {
for (var i = 0; i < this.length; i++) {
if (JSON.stringify(this[i]).indexOf(JSON.stringify(val)) != -1) {
this.splice(i, 1);
break;
}
}
};
export default {
data() {
return {
chooseList: []
};
},
watch: {
chooseList(n, o) {
this.$emit('chooseNode', n);
}
},
props: {
data: {
type: Array
}
},
methods: {
//
open(item,type) {
item.ifVisible = !item.ifVisible;
type == 1 ? this.$emit('fircheckitem',item) : this.$emit('twocheckitem',item)
},
//removeByvaluemain.js
choose(item) {
item.ifVisible = !item.ifVisible;
if (item.ifVisible) {
this.chooseList.push(item);
} else {
this.chooseList.removeByValue(item);
}
},
fircheckitem(item){
this.$emit('fircheckitem',item);
},
twocheckitem(item){
this.$emit('twocheckitem',item);
},
//
addMajor(){
this.$emit('addMajor');
},
editMajor(item){
this.$emit('editMajor',item);
},
delMajor(item,index){
this.$emit('delMajor',item,index);
},
//
addDepartment(item){
this.$emit('addDepartment',item);
},
editDepartment(item){
this.$emit('editDepartment',item);
},
delDepart(item,index){
this.$emit('delDepart',item,index);
},
//
addClass(item){
this.$emit('addClass',item);
},
editDepartment(item){
this.$emit('editDepartment',item);
},
delDepartment(item,index){
this.$emit('delDepartment',item,index);
},
//
isHasObj(arr, val) {
var flag = 0; //1 0
for (var i = 0; i < arr.length; i++) {
if (JSON.stringify(arr[i]).indexOf(JSON.stringify(val)) != -1) {
flag = 1;
}
}
if (flag == 1) {
return true;
} else {
return false;
}
}
}
};
</script>
<style lang="scss" scoped>
$insideColor: rgba(245, 242, 255, 0.8); //
$outColor: rgba(255, 255, 255, 0.8); //
//,item
@mixin public {
cursor: pointer;
font-size: 18px;
color: #333333;
display: flex;
align-items: center;
img {
height: 20px;
width: 20px;
margin-left: 10px;
}
}
.main {
width: 100%;
}
.item {
@include public;
width: 100%;
padding: 15px 0;
background:rgba(255,255,255,1);
box-shadow:1px 14px 29px 0px rgba(138,97,250,0.19);
border-radius:10px;
text-align: left;
margin-top: 20px;
}
.item:first{
margin-top: 0;
}
.item .empty{
width: 20px;
}
.edit{
width: 18px !important;
height: 18px !important;
margin-left: 10px;
}
.item2 {
@include public;
margin-top: 20px;
margin-left:60px
}
.item2:hover{
color: #9278FF;
}
//ul,li
ul,
li {
padding: 0;
margin: 0;
list-style: none;
}
// 使
.arrowTransform {
transition: 0.4s;
transform-origin: center;
transform: rotateZ(0deg);
}
.arrowTransformReturn {
transition: 0.4s;
transform-origin: center;
transform: rotateZ(90deg);
}
//
.checkBox {
width: 14px;
height: 14px;
border-radius: 7px;
margin-left: 10px;
margin-right: 10px;
border: 2px solid rgba(146, 120, 255, 1);
}
//
.isActive {
background: url('../../../assets/img/icon-yigouxuan.png');
background-size: 14px 14px;
}
.side_view{
// height: 800px;
padding: 40px 20px;
background-color: #fff;
box-shadow:-2px 0px 57px 0px rgba(192,189,216,0.39);
i {
color: #9278FF;
}
}
.side_icon{
text-align: right;
}
.side_icon i{
cursor:pointer;
font-size: 20px;
}
.side_tree{
width: 100%;
font-size: 14px;
color: #333;
i{
margin-left: 10px;
}
span{
margin-left: 5px;
font-size: 14px;
}
}
.fz{
font-size: 20px;
}
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,25 @@
/**
* @description 鉴权指令
* 当传入的权限当前用户没有时会移除该组件
* 用例<Tag v-auth>text</Tag> <Tag v-auth="'user:'">text</Tag>
* */
import store from '@/store'
export default {
inserted (el, binding, vnode) {
let btnText = ''
if(binding.value){
btnText = binding.value
}else{
btnText = `${vnode.context.$route.path}:${el.innerText}`
}
const btnPermissions = store.state.auth.btns
if (btnText && btnPermissions && btnPermissions.length) {
const isPermission = btnPermissions.includes(btnText)
if (!isPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
}
}
}

@ -0,0 +1,12 @@
/**
* @description 返回缺省值
* 传入的如果是null就返回'--'
* 用例<Tag :default="val">text</Tag> <Tag>{{val | default}}</Tag>
* */
const defaultShow = (val) => {
return val == null ? '--' : val
}
module.exports = {
defaultShow
}

@ -0,0 +1,14 @@
/**
* 插件
* */
import directiveAuth from '@/plugins/auth';
import throttle from '@/plugins/throttle';
export default {
async install (Vue, options) {
// 指令
Vue.directive('auth', directiveAuth);
Vue.directive('throttle', throttle);
}
}

@ -0,0 +1,140 @@
import axios from 'axios'
import util from '@/libs/util'
import router from '@/router/index'
import Setting from '@/setting'
const service = axios.create({
baseURL: Setting.apiBaseURL,
timeout: 10000000
})
// post请求头
service.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
// 请求拦截器
service.interceptors.request.use(config => {
util.getToken()
let token = util.local.get(Setting.tokenKey)
if(token) config.headers.token = token
return config
},err => {
util.errorMsg({
message: '退出登陆',
onClose: function () {
router.push({name: '/login'})
}
})
return Promise.reject(err)
})
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data
if(res.status == 200 || res.status == 10000) {
return Promise.resolve(res).catch(e => {})
}else if(!res.status){
return Promise.resolve(res).catch(e => {})
}else {
util.errorMsg(res.errmessage)
return Promise.reject(res)
}
},
// 服务器状态码不是200的情况
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
util.local.remove(Setting.storeKey)
util.local.remove(Setting.tokenKey)
util.errorMsg('登录过期,请重新登录')
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
})
}, 1000)
break
case 500:
util.errorMsg('网络错误')
break
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
util.local.remove(Setting.storeKey)
util.local.remove(Setting.tokenKey)
util.errorMsg('登录过期,请重新登录')
// 清除token
// store.commit('loginSuccess', null);
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
})
}, 1000)
break
// 404请求不存在
case 404:
util.errorMsg('网络请求不存在!')
break
// 其他错误,直接抛出错误提示
default:
util.errorMsg(error.response.data.message)
Promise.reject(res)
}
return Promise.reject(error.response)
}
}
);
function get(url, params){
return new Promise((resolve, reject) =>{
service.get(url, {params: params}).then(res => {
resolve(res)
}).catch(err => {
reject(err)
})
})
}
function post(url, params){
return new Promise((resolve, reject) =>{
service.post(url,params).then(res => {
resolve(res)
}).catch(err => {
reject(err.data)
})
})
}
function del(url, params){
return new Promise((resolve, reject) =>{
service.delete(url, {
params
}).then(res => {
resolve(res)
}).catch(err => {
reject(err.data)
})
})
}
function put(url, params){
return new Promise((resolve, reject) =>{
service.put(url, params).then(res => {
resolve(res)
}).catch(err => {
reject(err.data)
})
})
}
export { get,post,del,put }

@ -0,0 +1,18 @@
/**
* @description 节流指令
* 限制连续快速点击按钮
* 用例<Tag v-throttle>text</Tag>
* */
export default{
inserted (el, binding, vnode) {
el.addEventListener('click', () => {
if (!el.disabled) {
el.disabled = true
setTimeout(() => {
el.disabled = false
}, binding.value || 1000)
}
})
}
}

@ -0,0 +1,22 @@
import Vue from 'vue'
import Router from 'vue-router'
import routes from './routes'
import Setting from '@/setting'
Vue.use(Router)
const createRouter = () => new Router({
mode: Setting.routerMode,
    base: process.env.BASE_URL,
scrollBehavior: () => ({ y: 0 }),
routes
})
export function resetRouter () {
const newRouter = createRouter()
router.matcher = newRouter.matcher
}
let router = createRouter()
export default router

@ -0,0 +1,43 @@
import BasicLayout from '@/layouts/home'
const meta = {}
const pre = 'achievement-'
export default {
path: '/achievement',
name: 'achievement',
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import('@/pages/achievement/list'),
meta: { title: '成绩管理' }
},{
name: `${pre}vir`,
path: `vir`,
component: () => import('@/pages/achievement/vir'),
meta: { title: '成绩管理' }
},{
name: `${pre}teach`,
path: `teach`,
component: () => import('@/pages/achievement/teach'),
meta: { title: '成绩管理' }
},{
name: `${pre}ass`,
path: `ass`,
component: () => import('@/pages/achievement/ass'),
meta: { title: '成绩管理' }
},{
name: `${pre}show`,
path: `show`,
component: () => import('@/pages/achievement/show'),
meta: { title: '实验报告' }
},
]
};

@ -0,0 +1,29 @@
import BasicLayout from '@/layouts/home'
const meta = {}
const pre = 'assessment-'
export default {
path: '/assessment',
name: 'assessment',
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import('@/pages/assessment/list'),
meta: { title: '考核管理' }
},
{
name: `${pre}add`,
path: `add`,
component: () => import('@/pages/assessment/add/index.vue'),
meta: { title: '添加考核' }
},
]
};

@ -0,0 +1,23 @@
import BasicLayout from '@/layouts/home'
const meta = {}
const pre = 'evaluation-'
export default {
path: '/evaluation',
name: 'evaluation',
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import('@/pages/evaluation/list'),
meta: { title: '测评管理' }
},
]
};

@ -0,0 +1,29 @@
import BasicLayout from '@/layouts/home'
const meta = {}
const pre = 'project-'
export default {
path: '/project',
name: 'project',
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import('@/pages/project/list'),
meta: { title: '实验项目管理' }
},
{
name: `${pre}add`,
path: `add`,
component: () => import('@/pages/project/add'),
meta: { title: '新增项目' }
},
]
};

@ -0,0 +1,23 @@
import BasicLayout from '@/layouts/home'
const meta = {}
const pre = 'setting-'
export default {
path: '/setting',
name: 'setting',
redirect: {
name: `${pre}person`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}person`,
path: `person`,
component: () => import('@/pages/setting/person'),
meta: { title: '个人中心' }
},
]
};

@ -0,0 +1,23 @@
import BasicLayout from '@/layouts/home'
const meta = {}
const pre = 'student-'
export default {
path: '/student',
name: 'student',
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import('@/pages/student/list'),
meta: { title: '学生管理' }
},
]
};

@ -0,0 +1,23 @@
import BasicLayout from '@/layouts/home'
const meta = {}
const pre = 'system-'
export default {
path: '/system',
name: 'system',
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import('@/pages/system/list'),
meta: { title: '系统设置' }
},
]
};

@ -0,0 +1,27 @@
import router from './index'
import Setting from '@/setting'
import util from '@/libs/util'
router.beforeEach((to, from, next) => {
document.title = Setting.titleSuffix
const role = util.local.get(Setting.tokenKey)
if (!role && to.path !== '/login') {
next('/login')
} else if(role && to.path == '/login') {
next('/index')
} else {
let mg = from.query.mg
if(mg){
if(!to.query.mg){
next({
path: to.path,
query: {mg}
})
}else{
next()
}
}else{
next()
}
}
});

@ -0,0 +1,82 @@
import assessment from './modules/assessment'
import achievement from './modules/achievement'
import evaluation from './modules/evaluation'
import project from './modules/project'
import student from './modules/student'
import system from './modules/system'
import setting from './modules/setting'
import BasicLayout from '@/layouts/home'
const frameIn = [
{
path: '/',
redirect: '/login',
},
{
path: '/index',
redirect: '/assessment',
},
{
path: '/',
component: () => BasicLayout,
meta: { title: '首页' },
children: []
},
assessment,
achievement,
evaluation,
project,
student,
system,
setting,
]
/**
* 在主框架之外显示
*/
const frameOut = [
// 登录
{
path: '/login',
name: 'login',
meta: {
title: '登录'
},
component: () => import('@/pages/account/login')
}
];
/**
* 错误页面
*/
const errorPage = [
{
path: '/403',
name: '403',
meta: {
title: '403'
},
component: () => import('@/pages/exception/error/403')
},
{
path: '*',
name: '404',
meta: {
title: '404'
},
component: () => import('@/pages/exception/error/404')
}
];
// 导出需要显示菜单的
export const frameInRoutes = frameIn;
// 重新组织后导出
export default [
...frameIn,
...frameOut,
...errorPage
];

@ -0,0 +1,21 @@
/**
* 开发配置
* */
const env = process.env.NODE_ENV;
const Setting = {
// 是否使用 Mock 的数据,默认 开发环境为 true,生产环境为 false
isMock: true,
// 部署应用包时的基本 URL
publicPath: env === 'development' ? './' : '',
// 生产环境构建文件的目录名
outputDir: 'dist',
// 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。
assetsDir: 'static',
// 开发环境每次保存时 lint 代码,会将 lint 错误输出为编译警告
// true || false || error
lintOnSave: true,
};
module.exports = Setting;

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

Loading…
Cancel
Save