master
yujialong 4 years ago
commit 4fa16e2fd6
  1. 3
      .browserslistrc
  2. 22
      .gitignore
  3. 6
      .prettierrc
  4. 21
      LICENSE
  5. 197
      README.md
  6. 196
      README_EN.md
  7. 5
      babel.config.js
  8. 13615
      package-lock.json
  9. 37
      package.json
  10. 5
      postcss.config.js
  11. 17
      public/index.html
  12. BIN
      screenshots/wms1.png
  13. BIN
      screenshots/wms2.png
  14. BIN
      screenshots/wms3.png
  15. 23
      src/App.vue
  16. 165
      src/api/index.js
  17. BIN
      src/assets/img/account.png
  18. BIN
      src/assets/img/arrow-down.png
  19. BIN
      src/assets/img/close.png
  20. BIN
      src/assets/img/download.png
  21. 1
      src/assets/img/edit.svg
  22. BIN
      src/assets/img/icon-xiangyou.png
  23. BIN
      src/assets/img/icon-yigouxuan.png
  24. BIN
      src/assets/img/icon_.png
  25. BIN
      src/assets/img/icon_1.png
  26. BIN
      src/assets/img/login_bg.png
  27. BIN
      src/assets/img/logo-fill.png
  28. BIN
      src/assets/img/logo-full.png
  29. BIN
      src/assets/img/logo.png
  30. BIN
      src/assets/img/password.png
  31. BIN
      src/assets/img/station1.png
  32. BIN
      src/assets/img/station2.png
  33. BIN
      src/assets/img/station3.png
  34. BIN
      src/assets/img/station4.png
  35. BIN
      src/assets/img/station5.png
  36. BIN
      src/assets/img/system-fullname.png
  37. BIN
      src/assets/img/system-name.png
  38. BIN
      src/assets/img/upload.png
  39. 1
      src/assets/svg/edit.svg
  40. 30
      src/components/breadcrumb/index.vue
  41. 124
      src/components/pdf/index.vue
  42. 179
      src/components/quill/index.vue
  43. 16
      src/components/quill/options.js
  44. 30
      src/i18n/index.js
  45. 28
      src/layouts/footer/index.vue
  46. 103
      src/layouts/header/index.vue
  47. 92
      src/layouts/home/index.vue
  48. 269
      src/layouts/navbar/index.vue
  49. 141
      src/layouts/sidebar/index.vue
  50. 185
      src/layouts/tags/index.vue
  51. 25
      src/libs/auth/generateBtnPermission.js
  52. 6
      src/libs/bus.js
  53. 234
      src/libs/core.js
  54. 16
      src/libs/resize/index.js
  55. 41
      src/libs/route/addRoutes.js
  56. 25
      src/libs/route/generateRoutes.js
  57. 6
      src/libs/route/resetRouter.js
  58. 58
      src/main.js
  59. 56
      src/pages/403.vue
  60. 56
      src/pages/404.vue
  61. 250
      src/pages/addCourse.vue
  62. 248
      src/pages/addarticle.vue
  63. 504
      src/pages/addcustomer.vue
  64. 411
      src/pages/addmatch.vue
  65. 114
      src/pages/backstage.vue
  66. 156
      src/pages/classification.vue
  67. 204
      src/pages/content.vue
  68. 58
      src/pages/course.vue
  69. 705
      src/pages/courseConfig.vue
  70. 210
      src/pages/courseList.vue
  71. 448
      src/pages/courseSection.vue
  72. 245
      src/pages/dashboard.vue
  73. 46
      src/pages/i18n.vue
  74. 225
      src/pages/icon.vue
  75. 374
      src/pages/information.vue
  76. 205
      src/pages/login.vue
  77. 281
      src/pages/match.vue
  78. 51
      src/pages/matchDetail.vue
  79. 400
      src/pages/matchintro.vue
  80. 160
      src/pages/matchprogress.vue
  81. 153
      src/pages/matchsignup.vue
  82. 275
      src/pages/organization.vue
  83. 434
      src/pages/personalcenter.vue
  84. 281
      src/pages/role.vue
  85. 671
      src/pages/staff.vue
  86. 68
      src/pages/system.vue
  87. 474
      src/pages/user.vue
  88. 25
      src/plugins/auth/index.js
  89. 15
      src/plugins/index.js
  90. 398
      src/plugins/requests/index.js
  91. 18
      src/plugins/throttle/index.js
  92. 27
      src/router/index.js
  93. 33
      src/router/permission.js
  94. 72
      src/router/routes.js
  95. 21
      src/setting.env.js
  96. 116
      src/setting.js
  97. 85
      src/store/index.js
  98. 359
      src/styles/common.scss
  99. 7
      src/styles/default/index.scss
  100. BIN
      src/styles/font/YouSheBiaoTiHei.ttf
  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,197 @@
# vue-manage-system
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.8.2-brightgreen.svg" alt="element-ui">
</a>
<a href="https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
<a href="https://github.com/lin-xin/vue-manage-system/releases">
<img src="https://img.shields.io/github/release/lin-xin/vue-manage-system.svg" alt="GitHub release">
</a>
<a href="https://lin-xin.gitee.io/example/work/#/donate">
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
</a>
基于 Vue + Element UI 的后台管理系统解决方案。[线上地址](https://lin-xin.gitee.io/example/work/)
> React + Ant Design 的版本正在开发中,仓库地址:[react-manage-system](https://github.com/lin-xin/react-manage-system)
[English document](https://github.com/lin-xin/manage-system/blob/master/README_EN.md)
## 项目截图
### 登录
![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms3.png)
### 默认皮肤
![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms1.png)
### 浅绿色皮肤
![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms2.png)
## 赞赏
请作者喝杯咖啡吧!(微信号:linxin_20)
![微信扫一扫](https://lin-xin.gitee.io/images/weixin.jpg)
## 特别鸣谢
- [实验楼](https://www.shiyanlou.com?source=vue-manage-system)
## 前言
该方案作为一套多功能的后台框架模板,适用于绝大部分的后台管理系统(Web Management System)开发。基于 vue.js,使用 vue-cli3 脚手架,引用 Element UI 组件库,方便开发快速简洁好看的组件。分离颜色样式,支持手动切换主题色,而且很方便使用自定义主题色。
## 功能
- [x] Element UI
- [x] 登录/注销
- [x] Dashboard
- [x] 表格
- [x] Tab 选项卡
- [x] 表单
- [x] 图表 :bar_chart:
- [x] 富文本编辑器
- [x] markdown 编辑器
- [x] 图片拖拽/裁剪上传
- [x] 支持切换主题色 :sparkles:
- [x] 列表拖拽排序
- [x] 权限测试
- [x] 404 / 403
- [x] 三级菜单
- [x] 自定义图标
- [x] 可拖拽弹窗
- [x] 国际化
## 安装步骤
```
git clone https://github.com/lin-xin/vue-manage-system.git // 把模板下载到本地
cd vue-manage-system // 进入模板目录
npm install // 安装项目依赖,等待安装完成之后,安装失败可用 cnpm 或 yarn
// 开启服务器,浏览器访问 http://localhost:8080
npm run serve
// 执行构建命令,生成的dist文件夹放在服务器下即可访问
npm run build
```
## 组件使用说明与演示
### vue-schart
vue.js 封装 sChart.js 的图表组件。访问地址:[vue-schart](https://github.com/linxin/vue-schart)
<p><a href="https://www.npmjs.com/package/vue-schart"><img src="https://img.shields.io/npm/dm/vue-schart.svg" alt="Downloads"></a></p>
```html
<template>
<div>
<schart class="wrapper" canvasId="myCanvas" :options="options"></schart>
</div>
</template>
<script>
import Schart from 'vue-schart'; // 导入Schart组件
export default {
data() {
return {
options: {
type: 'bar',
title: {
text: '最近一周各品类销售图'
},
labels: ['周一', '周二', '周三', '周四', '周五'],
datasets: [
{
label: '家电',
data: [234, 278, 270, 190, 230]
},
{
label: '百货',
data: [164, 178, 190, 135, 160]
},
{
label: '食品',
data: [144, 198, 150, 235, 120]
}
]
}
};
},
components: {
Schart
}
};
</script>
<style>
.wrapper {
width: 7rem;
height: 5rem;
}
</style>
```
## 其他注意事项
### 一、如果我不想用到上面的某些组件呢,那我怎么在模板中删除掉不影响到其他功能呢?
举个栗子,我不想用 Vue-Quill-Editor 这个组件,那我需要分四步走。
第一步:删除该组件的路由,在目录 src/router/index.js 中,找到引入改组件的路由,删除下面这段代码。
```JavaScript
{
// 富文本编辑器组件
path: '/editor',
component: resolve => require(['../components/page/VueEditor.vue'], resolve)
},
```
第二步:删除引入该组件的文件。在目录 src/components/page/ 删除 VueEditor.vue 文件。
第三步:删除该页面的入口。在目录 src/components/common/Sidebar.vue 中,找到该入口,删除下面这段代码。
```js
{
index: 'editor',
title: '富文本编辑器'
},
```
第四步:卸载该组件。执行以下命令:
npm un vue-quill-editor -S
完成。
### 二、如何切换主题色呢?
第一步:打开 src/main.js 文件,找到引入 element 样式的地方,换成浅绿色主题。
```javascript
import 'element-ui/lib/theme-default/index.css'; // 默认主题
// import './assets/css/theme-green/index.css'; // 浅绿色主题
```
第二步:打开 src/App.vue 文件,找到 style 标签引入样式的地方,切换成浅绿色主题。
```javascript
@import "./assets/css/main.css";
@import "./assets/css/color-dark.css"; /*深色主题*/
/*@import "./assets/css/theme-green/color-green.css"; !*浅绿色主题*!*/
```
第三步:打开 src/components/common/Sidebar.vue 文件,找到 el-menu 标签,把 background-color/text-color/active-text-color 属性去掉即可。
## License
[MIT](https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE)

@ -0,0 +1,196 @@
# vue-manage-system
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.8.2-brightgreen.svg" alt="element-ui">
</a>
<a href="https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
<a href="https://github.com/lin-xin/vue-manage-system/releases">
<img src="https://img.shields.io/github/release/lin-xin/vue-manage-system.svg" alt="GitHub release">
</a>
<a href="https://lin-xin.gitee.io/example/work/#/donate">
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
</a>
The web management system solution based on Vue2 and Element-UI。[live demo](https://lin-xin.gitee.io/example/work/)
## Donation
![WeChat](https://lin-xin.gitee.io/images/weixin.jpg)
## Preface
The scheme as a set of multi-function background frame templates, suitable for most of the WEB management system development. Convenient development fast simple good components based on Vue2 and Element-UI. Color separation of color style, support manual switch themes, and it is convenient to use a custom theme color.
## Function
- [x] Element-UI
- [x] Login/Logout
- [x] Dashboard
- [x] Table
- [x] Tabs
- [x] From
- [x] Chart :bar_chart:
- [x] Editor
- [x] Markdown
- [x] Upload pictures by clipping or dragging
- [x] Support manual switch themes :sparkles:
- [x] List drag sort
- [x] Permission
- [x] 404 / 403
- [x] Three level menu
- [x] Custom icon
## Installation steps
git clone https://github.com/lin-xin/vue-manage-system.git // Clone templates
cd vue-manage-system // Enter template directory
npm install // Installation dependency
## Local development
// Open server and access http://localhost:8080 in browser
npm run serve
## Constructing production
// Constructing project
npm run build
## Component description and presentation
### vue-schart
Vue.js wrapper for sChart.js. Github : [vue-schart](https://github.com/linxin/vue-schart)
```html
<template>
<div>
<schart class="wrapper" canvasId="myCanvas" :options="options"></schart>
</div>
</template>
<script>
import Schart from 'vue-schart'; // 导入Schart组件
export default {
data() {
return {
options: {
type: 'bar',
title: {
text: '最近一周各品类销售图'
},
labels: ['周一', '周二', '周三', '周四', '周五'],
datasets: [
{
label: '家电',
data: [234, 278, 270, 190, 230]
},
{
label: '百货',
data: [164, 178, 190, 135, 160]
},
{
label: '食品',
data: [144, 198, 150, 235, 120]
}
]
}
};
},
components: {
Schart
}
};
</script>
<style>
.wrapper {
width: 7rem;
height: 5rem;
}
</style>
```
### element-ui
A desktop component library based on vue.js2.0 . Github : [element](http://element.eleme.io/#/zh-CN/component/layout)
### Vue-Quill-Editor
Quill editor component for Vue2. Github : [vue-quill-editor](https://github.com/surmon-china/vue-quill-editor)
### mavonEditor
A markdown editor based on Vue that supports a variety of personalized features. Github: [mavonEditor](https://github.com/hinesboy/mavonEditor)
### vue-cropperjs
A Vue wrapper component for cropperjs. Github: [vue-cropperjs](https://github.com/Agontuk/vue-cropperjs)
## Notice
### 一、If I don't want to use some components, how can I delete it?
For example, I don't want to use the Vue-Quill-Editor component, I need to take four steps.
The first step to remove the component of the routing. Enter 'src/router/index.js' and delete the code below.
```JavaScript
{
path: '/editor',
component: resolve => require(['../components/page/VueEditor.vue'], resolve)
},
```
Second,delete the component files. Enter 'src/components/page/' and delete 'VueEditor.vue' file.
The third step is to delete the entry. Enter 'src/components/common/Sidebar.vue' and delete the code below.
```js
{
index: 'editor',
title: '富文本编辑器'
},
```
Finally, uninstall this component.
npm un vue-quill-editor -S
Complete!
### 二、How to switch themes?
The first step to enter 'src/main.js' and change into green theme.
```javascript
import 'element-ui/lib/theme-default/index.css'; // default theme
// import '../static/css/theme-green/index.css'; // green theme
```
The second step to enter 'src/App.vue' and change into green theme.
```javascript
@import "../static/css/main.css";
@import "../static/css/color-dark.css"; /*深色主题*/
/*@import "../static/css/theme-green/color-green.css"; !*浅绿色主题*!*/
```
Finally,enter 'src/components/common/Sidebar.vue' and find el-menu Tags,delete 'background-color/text-color/active-text-color'。
## Screenshot
### Default theme
![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms1.png)
### Green theme
![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms2.png)
## License
[MIT](https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE)

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

13615
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,37 @@
{
"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",
"element-theme": "^2.0.1",
"element-ui": "^2.13.0",
"lodash": "^4.17.20",
"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.24.2",
"vuex": "^3.1.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.9.0",
"@vue/cli-service": "^3.9.0",
"element-theme-chalk": "^2.13.0",
"node-sass": "^4.14.1",
"sass-loader": "^8.0.0",
"vue-template-compiler": "^2.6.10"
}
}

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

@ -0,0 +1,17 @@
<!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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

@ -0,0 +1,23 @@
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
import Setting from '@/setting';
export default {
name: 'App',
created () {
//sessionStorage
if (sessionStorage.getItem(Setting.storeKey) ) {
this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(sessionStorage.getItem(Setting.storeKey))))
}
//vuexsessionStorage
window.addEventListener("beforeunload",()=>{
sessionStorage.getItem(Setting.usernameKey) && sessionStorage.setItem(Setting.storeKey,JSON.stringify(this.$store.state))
})
}
}
</script>

@ -0,0 +1,165 @@
import Setting from '@/setting';
let host = Setting.apiBaseURL
// let host = 'http://192.168.31.117'//宁本地
// let host = 'http://192.168.31.137:8001'//陈本地
export default {
logins: `${host}/management/userInfo/login`, //登录 
// 查询省份城市
queryCity: `${host}/enterprise/city/queryCity`,
queryProvince: `${host}/enterprise/province/queryProvince`,
// 个人中心
uploadUserAvatars: `http://www.liuwanr.cn/liuwanr/user/uploadUserAvatars`,
userinfoUpdate:`${host}/management/userInfo/update`,//个人中心信息修改
userinfo:`${host}/management/userInfo/getUserInfo`,//个人中心信息展示
getAccount:`${host}/management/userInfo/getAccount`,//账号判重
// 学生管理
addStudent: `${host}/management/student/addStudent`,
deleteStudents: `${host}/management/student/deleteStudents`,
getStudent: `${host}/management/student/getStudent`,
queryStudent: `${host}/management/student/list`,
updateStudent: `${host}/management/student/updateStudent`,
// 组织架构
addStaffPro: `${host}/management/staffProfessionalArchitecture/addStaffProfessionalArchitecture`,
deleteStaffPro: `${host}/management/staffProfessionalArchitecture/deleteStaffProfessionalArchitecture`,
queryStaffPAN: `${host}/management/staffProfessionalArchitecture/queryStaffPAN`,
queryStaffPro: `${host}/management/staffProfessionalArchitecture/queryStaffProfessionalArchitecture`,
updateStaffPro: `${host}/management/staffProfessionalArchitecture/updateStaffProfessionalArchitecture`,
getWorkNumber: `${host}/management/staff/getWorkNumber`,
// 年级
addStaffGrade: `${host}/management/staffGrade/addStaffGrade`,
deleteStaffGrade: `${host}/management/staffGrade/deleteStaffGrade`,
queryStaffGrade: `${host}/management/staffGrade/queryStaffGrade`,
queryStaffName: `${host}/management/staffGrade/queryStaffName`,
updateStaffGrade: `${host}/management/staffGrade/updateStaffGrade`,
// 员工管理
addStaff: `${host}/management/staff/addStaff`,
deleteStaffs: `${host}/management/staff/deleteStaffs`,
getStaff: `${host}/management/staff/getStaff`,
queryStaff: `${host}/management/staff/enterpriseList`,
updateStaff: `${host}/management/staff/updateStaff`,
exportFailureStaff: `${host}/management/staff/exportFailure`,
uploadFileStaff: `${host}/management/staff/uploadFile`,
downloadStaffTemp: `https://cj-oss.oss-cn-guangzhou.aliyuncs.com/20210208/xlsx/1358714535309500416.xlsx`,
// 角色管理
getRole: `${host}/management/role/get`,
queryRoles: `${host}/management/role/list`,
removeRole: `${host}/management/role/batchRemove`,
saveOrUpdate: `${host}/management/role/saveOrUpdate`,
getRoles: `${host}/management/role/getRole`,
// 权限菜单管理
doAssign: `${host}/management/permission/doAssign`,
queryPermissionMenu: `${host}/management/permission/queryPermissionMenu`,
toAssign: `${host}/management/permission/toAssign`,
// 学校管理
addClient: `${host}/enterprise/client/addClient`,
deleteClient: `${host}/enterprise/client/deleteClient`,
queryClient: `${host}/enterprise/client/list`,
updateClient: `${host}/enterprise/client/updateClient`,
getClient: `${host}/enterprise/client/getClient`,
getClientName: `${host}/enterprise/client/getClientName`,
// 用户管理
addUser: `${host}/enterprise/user/addUser`,
deleteUser: `${host}/enterprise/user/deleteUser`,
queryUser: `${host}/enterprise/user/list`,
updateUser: `${host}/enterprise/user/updateUser`,
uploadFileUser: `${host}/enterprise/user/uploadFile`,
exportFailureUser: `${host}/enterprise/user/exportFailure`,
downloadUserTemp: 'https://cj-oss.oss-cn-guangzhou.aliyuncs.com/20210310/xlsx/1369497713188036608.xlsx',
addApplicant: `${host}/enterprise/match/applicant/addApplicant`,
disableContests: `${host}/enterprise/match/applicant/disableContests`,
excelExport: `${host}/enterprise/match/applicant/excelExport`,
queryApplicantByCondition: `${host}/enterprise/match/applicant/queryApplicantByCondition`,
disableApplicant: `${host}/enterprise/match/applicant/disableApplicant`,
batchExport: `${host}/enterprise/match/applicant/batchExport`,
// 赛事管理
addContest: `${host}/enterprise/match/contest/addContest`,
deleteContest: `${host}/enterprise/match/contest/deleteContest`,
editContest: `${host}/enterprise/match/contest/editContest`,
publishContest: `${host}/enterprise/match/contest/publishContest`,
getContest: `${host}/enterprise/match/contest/getContest`,
queryContestByCondition: `${host}/enterprise/match/contest/queryContestByCondition`,
// 赛事进度
addContestProgress: `${host}/enterprise/match/contest-progress/addContestProgress`,
deleteContestProgress: `${host}/enterprise/match/contest-progress/deleteContestProgress`,
getContestProgress: `${host}/enterprise/match/contest-progress/getContestProgress`,
editContestProgress: `${host}/enterprise/match/contest-progress/editContestProgress`,
// 栏目管理
addColumn: `${host}/enterprise/information/column/addColumn`,
deleteColumn: `${host}/enterprise/information/column/deleteColumn`,
editColumn: `${host}/enterprise/information/column/editColumn`,
queryAllColumns: `${host}/enterprise/information/column/queryAllColumns`,
reorder: `${host}/enterprise/information/column/reorder`,
// 内容管理
addArticle: `${host}/enterprise/information/article/addArticle`,
deleteArticles: `${host}/enterprise/information/article/deleteArticles`,
editArticle: `${host}/enterprise/information/article/editArticle`,
enableArticle: `${host}/enterprise/information/article/enableArticle`,
getArticle: `${host}/enterprise/information/article/getArticle`,
getArticles: `${host}/enterprise/information/article/getArticles`,
queryArticleByCondition: `${host}/enterprise/information/article/queryArticleByCondition`,
articleSort: `${host}/enterprise/information/article/articleSort`,
// 课程权限
addBuiltInCourse: `${host}/management/schoolCourse/addBuiltInCourse`,
deleteBuiltInCourse: `${host}/management/schoolCourse/deleteBuiltInCourse`,
enableGlCourse: `${host}/management/edu/course/enableQyCourse`,
queryBuiltInCourseByCondition: `${host}/management/schoolCourse/queryBuiltInCourseByCondition`,
// 课程管理
queryCourseByCondition: `${host}/management/schoolCourse/queryCourseByCondition`,
addCourse: `${host}/management/edu/course/addCourse`,
deleteCourse: `${host}/management/edu/course/deleteCourse`,
deleteCourses: `${host}/management/edu/course/deleteCourses`,
editCourse: `${host}/management/edu/course/editCourse`,
enableCourse: `${host}/management/edu/course/enableQyCourse`,
getCourse: `${host}/management/edu/course/getCourse`,
queryAllClassification: `${host}/management/schoolClassification/queryQyClassification`,
deleteClassification: `${host}/management/edu/courseClassification/deleteClassification`,
addClassification: `${host}/management/edu/courseClassification/addClassification`,
editClassification: `${host}/management/edu/courseClassification/editClassification`,
// 课程标签管理
addLabel: `${host}/management/edu/courseLabel/addLabel`,
deleteLabel: `${host}/management/edu/courseLabel/deleteLabel`,
editLabel: `${host}/management/edu/courseLabel/editLabel`,
queryAllLabel: `${host}/management/edu/courseLabel/queryAllLabel`,
// 课程章节管理
addChapter: `${host}/management/edu/courseChapter/addChapter`,
chapterReorder: `${host}/management/edu/courseChapter/chapterReorder`,
deleteChapter: `${host}/management/edu/courseChapter/deleteChapter`,
editChapter: `${host}/management/edu/courseChapter/editChapter`,
queryChaptersAndSubsections: `${host}/management/edu/courseChapter/queryChaptersAndSubsections`,
reorder: `${host}/management/edu/courseChapter/reorder`,
// 课程小节管理
addSubsection: `${host}/management/edu/courseSubsection/addSubsection`,
deleteSubsection: `${host}/management/edu/courseSubsection/deleteSubsection`,
editSubsection: `${host}/management/edu/courseSubsection/editSubsection`,
getSubsection: `${host}/management/edu/courseSubsection/getSubsection`,
// 视频管理
fileDeletion: `${host}/oss/manage/fileDeletion`,
fileupload: `${host}/oss/manage/fileupload`,
getPlayAuth: `${host}/oss/manage/getPlayAuth`,
removeMoreVideo: `${host}/oss/manage/removeMoreVideo`,
removeVideo: `${host}/oss/manage/removeVideo`,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

@ -0,0 +1 @@
<svg t="1604370117041" 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="#cb221c"></path></svg>

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

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: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

@ -0,0 +1 @@
<svg t="1604370117041" 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="#cb221c"></path></svg>

After

Width:  |  Height:  |  Size: 875 B

@ -0,0 +1,30 @@
<template>
<div class="breadcrumb">
<span class="cur">当前位置</span>
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">超竞教育端</el-breadcrumb-item>
<el-breadcrumb-item v-for="(item,index) in pages" :key="index" :to="{ path: index == pages.length - 1 ? curRoute : route }">{{item}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script>
export default {
props: ['data','route'],
data() {
return {
pages: this.data.split('/'),
curRoute: this.$route.path
};
},
methods: {
update(data){
console.log(2222,data)
this.pages = data.split('/')
}
}
};
</script>
<style lang="scss" scoped>
</style>

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

@ -0,0 +1,179 @@
<template>
<div class="quill" :class="classes">
<div ref="editor" :style="styles" v-loading="loading"></div>
<el-upload :action="this.api.fileupload" :before-upload="beforeUpload" :on-success="editorUploadSuccess" style="display: none">
<el-button class="editorUpload" size="small" type="primary">点击上传</el-button>
</el-upload>
</div>
</template>
<script>
import Quill from 'quill';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import toolbarOptions from './options'
export default {
name: 'quill',
props: {
value: {
type: String,
default: ''
},
uploading: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
border: {
type: Boolean,
default: false
},
height: {
type: Number
},
minHeight: {
type: Number
}
},
data () {
return {
Quill: null,
currentValue: '',
options: {
theme: 'snow',
bounds: document.body,
debug: 'warn',
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
'image': function (value) {
if (value) {
// iview
document.querySelector('.editorUpload').click()
} else {
this.Quill.format('image', false);
}
}
}
}
},
placeholder: '',
readOnly: this.readonly,
},
loading: false
}
},
computed: {
classes () {
return [
{
'quill-no-border': !this.border
}
];
},
styles () {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
}
},
watch: {
value: {
handler (val) {
if (val !== this.currentValue) {
this.currentValue = val;
if (this.Quill) {
this.Quill.pasteHTML(this.value);
}
}
},
immediate: true
}
},
mounted () {
this.init();
},
beforeDestroy () {
//
this.Quill = null;
},
methods: {
init () {
const editor = this.$refs.editor;
//
this.Quill = new Quill(editor, this.options);
//
this.Quill.pasteHTML(this.currentValue);
this.$nextTick(() => {
document.querySelector('.content').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
this.$emit('update:uploading',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.successMsg('图片插入失败')
}
this.loading = false
this.$emit('update:uploading',false)
},
}
}
</script>
<style lang="scss" scoped>
.quill-no-border{
.ql-toolbar.ql-snow{
border: none;
border-bottom: 1px solid #e8eaec;
}
.ql-container.ql-snow{
border: none;
}
}
</style>

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

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

@ -0,0 +1,28 @@
<template>
<div>
<div class="copyright">广州超竞教育投资有限公司版权所有</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;
}
</style>

@ -0,0 +1,103 @@
<template>
<div>
<div class="header">
<img class="system-name" src="../../assets/img/system-fullname.png">
<el-dropdown class="user-wrap" @command="userCommand">
<div class="user">
<el-avatar :size="40" :src="avatar"></el-avatar>
<span class="username">{{username}}</span>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="help">用户手册</el-dropdown-item>
<el-dropdown-item command="person">个人资料</el-dropdown-item>
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<pdf :visible.sync="pdfVisible" :src.sync="pdfSrc"></pdf>
</div>
</template>
<script>
import bus from '@/libs/bus';
import Setting from '@/setting';
import pdf from '@/components/pdf'
export default {
data() {
return {
pdfVisible: false,
pdfSrc: '',
avatar: this.$store.state.avatar ? this.$store.state.avatar : 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
showBackList: Setting.layout.hideNavList
};
},
components: { pdf },
computed: {
username() {
let username = sessionStorage.getItem(Setting.usernameKey);
return username ? username : this.name;
},
showBack(){
let route = this.$route.name
if(this.showBackList.includes(route)) return true
return false
}
},
mounted(){
bus.$on('updateAvatar',avatar => {
this.avatar = avatar
})
},
methods: {
loginout() {
sessionStorage.removeItem(Setting.usernameKey);
sessionStorage.removeItem(Setting.storeKey);
location.reload()
},
back(){
this.$route.name != 'addarticle' ? this.$router.push('match') : this.$router.back()
},
userCommand(command){
console.log(command)
if(command == 'help'){
this.pdfVisible = true
this.pdfSrc = 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20201125/pdf/1331502965949227008.pdf'
}else if(command == 'person'){
this.$router.push('personalCenter')
}else{
this.loginout()
}
}
},
};
</script>
<style lang="scss" scoped>
.header {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 40px 20px 24px;
font-size: 16px;
color: #333;
background-color: #fff;
box-sizing: border-box;
.system-name {
width: 326px;
}
.user-wrap {
display: flex;
align-items: center;
.user{
display: inline-flex;
align-items: center;
cursor: pointer;
.username{
margin-left: 10px;
color: #000;
font-size: 16px;
}
}
}
}
</style>

@ -0,0 +1,92 @@
<template>
<div class="main">
<v-navbar class="nav"></v-navbar>
<div class="layout">
<v-head></v-head>
<div class="content">
<transition name="move" mode="out-in">
<keep-alive :include="tagsList">
<router-view class="view"></router-view>
</keep-alive>
</transition>
<el-backtop target=".content"></el-backtop>
<v-footer ref="footer"></v-footer>
</div>
</div>
</div>
</template>
<script>
import vHead from '../header/index.vue';
import vNavbar from '../navbar/index.vue';
import vSidebar from '../sidebar/index.vue';
import vFooter from '../footer'
import bus from '@/libs/bus';
import Setting from '@/setting';
export default {
data() {
return {
tagsList: [],
collapse: false,
showSidebar: false,
hideNavList: Setting.layout.hideNavList
};
},
components: {
vHead,
vNavbar,
vSidebar,
vFooter
},
computed: {
hideSidebar() {
let route = this.$route.name
if(this.hideNavList.includes(route)) return false
return true
}
},
created() {
bus.$on('collapse-content', msg => {
this.collapse = msg;
});
this.showSidebar = this.$store.state.sidebarMenu
bus.$on('showMenu', status => {
this.showSidebar = false
this.$nextTick(() => {
this.showSidebar = status
})
});
// 使keep-alive
bus.$on('tags', msg => {
let arr = [];
for (let i = 0, len = msg.length; i < len; i++) {
msg[i].name && arr.push(msg[i].name);
}
this.tagsList = arr;
});
}
};
</script>
<style lang="scss" scoped>
.main{
display: flex;
min-width: 1300px;
height: 100%;
overflow: hidden;
.nav{
width: 220px;
}
.layout{
width: calc(100% - 220px);
.content{
height: calc(100vh - 80px);
padding: 24px 24px 0;
overflow: auto;
.view{
min-height: calc(100% - 60px);
}
}
}
}
</style>

@ -0,0 +1,269 @@
<template>
<div>
<div class="logo">
<img src="../../assets/img/logo-full.png" width="125">
</div>
<el-menu
class="sidebar-el-menu"
:default-active="onRoutes"
:collapse="collapse"
background-color="#141414"
text-color="#fff"
active-text-color="#fff"
unique-opened
@select="menuSelect"
>
<!-- 第一层 -->
<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">
<!-- 如果第二层有子菜单则继续循环 -->
<template v-if="subItem.subs">
<el-submenu :index="subItem.index" :key="subItem.index">
<template slot="title">
<span slot="title">{{ subItem.title }}</span>
</template>
<!-- <el-menu-item v-for="(threeItem,i) in subItem.subs" :key="i" :index="threeItem.index">{{ threeItem.title }}</el-menu-item> -->
<!-- 第三层 -->
<template v-for="subItem2 in subItem.subs">
<!-- 如果第三层有子菜单则继续循环 -->
<template v-if="subItem2.subs">
<el-submenu :index="subItem2.index" :key="subItem2.index">
<template slot="title">
<span slot="title">{{ subItem2.title }}</span>
</template>
<!-- <el-menu-item v-for="(fourItem,i) in subItem2.subs" :key="i" :index="fourItem.index">{{ fourItem.title }}</el-menu-item> -->
<!-- 第四层 -->
<template v-for="subItem3 in subItem2.subs">
<!-- 如果第四层有子菜单则继续循环 -->
<template v-if="subItem3.subs">
<el-submenu :index="subItem3.index" :key="subItem3.index">
<template slot="title">
<!-- <i :class="item.icon"></i> -->
<!-- <span slot="title">{{ subItem2.title }}</span> -->
{{ subItem3.title }}
</template>
<el-menu-item v-for="(fiveItem,i) in subItem3.subs" :key="i" :index="fiveItem.index">{{ fiveItem.title }}</el-menu-item>
</el-submenu>
</template>
<!-- 如果第四层没有子菜单 -->
<el-menu-item v-else :index="subItem3.index" :key="subItem3.index">{{ subItem3.title }}</el-menu-item>
</template>
</el-submenu>
</template>
<!-- 如果第三层没有子菜单 -->
<el-menu-item v-else :index="subItem2.index" :key="subItem2.index">{{ subItem2.title }}</el-menu-item>
</template>
</el-submenu>
</template>
<!-- 如果第二层没有子菜单 -->
<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 bus from '@/libs/bus';
import Setting from '@/setting';
export default {
data() {
return {
collapse: false,
defaultMenus: [
{
icon: 'el-icon-lx-home',
index: 'dashboard',
title: '学校信息管理'
},
{
icon: 'el-icon-user',
index: 'user',
title: '学校用户管理'
},
{
icon: 'el-icon-news',
index: 'course',
title: '课程资源管理'
},
{
icon: 'el-icon-monitor',
index: 'backstage',
title: '实训系统后台'
},
{
icon: 'el-icon-school',
index: 'match',
title: '赛事信息管理'
},
{
icon: 'el-icon-document',
index: 'information',
title: '官方资讯管理',
subs: []
},
{
icon: 'el-icon-takeaway-box',
index: 'system',
title: '平台分管设置'
}
],
menus: [],
actives: {
dashboard: ['addcustomer'],
information: ['content','addarticle'],
match: ['addmatch'],
course: ['addCourse','courseConfig','courseSection']
},
};
},
computed: {
onRoutes() {
let actives = this.actives
for(let i in this.actives){
if(actives[i].includes(this.$route.name)) return i
}
return this.$route.name
}
},
created() {
this.initMenu()
// Event Bus
bus.$on('collapse', msg => {
this.collapse = msg;
bus.$emit('collapse-content', msg);
});
},
methods: {
initMenu(){
if(Setting.dynamicRoute){
let routes = this.$store.state.routes[1].children
let menus = []
let showContent = false
this.defaultMenus.map(e => {
routes.find(n => n.path == e.index) && menus.push(e)
if(e.index == 'information'){
if(routes.find(n => n.path == 'information')){
menus.map(n => {
if(n.index == 'information'){
n.subs.push({
index: 'information',
title: '栏目管理',
})
}
})
}
if(routes.find(n => n.path == 'content')){
showContent = true
menus.map(n => {
if(n.index == 'information'){
n.subs.push({
title: '内容管理',
index: 'contents',
subs: []
})
}
})
}
}
})
this.menus = menus
this.$nextTick(() => {
setTimeout(() => {
showContent && this.getContent()
},500)
})
this.$store.commit('addIndex',{path: menus[0].index})
}else{
this.menus = this.defaultMenus
}
},
getContent() {
let data = {
page: 1,
size: 10000
}
this.$get(this.api.queryAllColumns,data).then(res => {
let contentMenu = []
res.data.columnTree.map(n => {
let temp = {
index: n.id,
title: n.name
}
if(n.secondColumn.length){
temp.subs = []
n.secondColumn.map(e => {
temp.subs.push({
index: e.id,
title: e.name
})
})
}
contentMenu.push(temp)
})
let menus = this.menus
menus.map(n => {
if(n.index == 'information'){
n.subs.map(e => {
if(e.index == 'contents') e.subs = contentMenu
})
}
})
this.menus = menus
}).catch(res => {})
},
menuSelect(index,indexPath){
if(!isNaN(index)){
this.$router.push(`content?id=${index}`)
}else{
this.$router.push(index)
}
}
}
};
</script>
<style lang="scss" scoped>
.nav{
height: 100%;
background-color: #141414;
overflow: auto;
.logo{
padding: 20px 0;
text-align: center;
}
/deep/.el-menu{
border-right: 0 !important;
.el-menu-item.is-active{
background-color: #CC221C !important;
}
}
}
.sidebar::-webkit-scrollbar {
width: 0;
}
.sidebar-el-menu:not(.el-menu--collapse) {
width: 100%;
}
.sidebar > ul {
height: 100%;
}
</style>

@ -0,0 +1,141 @@
<template>
<div>
<el-menu
:default-active="onRoutes"
:collapse="collapse"
unique-opened
router
>
<template v-for="item in menuList[curMenu]">
<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 bus from '@/libs/bus';
import Setting from '@/setting';
export default {
data() {
return {
collapse: false,
curMenu: this.$store.state.sidebarMenu,
defaultInfoMenu: [
{
icon: 'el-icon-s-grid',
index: 'information',
title: '栏目管理'
},
{
icon: 'el-icon-c-scale-to-original',
index: 'content',
title: '内容管理'
}
],
menuList: {
match: [
{
icon: 'el-icon-lx-copy',
index: 'matchintro',
title: '大赛详情'
},
{
icon: 'el-icon-aim',
index: 'matchprogress',
title: '竞赛进展'
},
{
icon: 'el-icon-user',
index: 'matchsignup',
title: '报名人员'
},
],
info: []
},
menus: []
};
},
computed: {
onRoutes() {
return this.$route.name
}
},
created() {
Setting.dynamicRoute && this.initMenu()
// Event Bus
bus.$on('collapse', msg => {
this.collapse = msg;
bus.$emit('collapse-content', msg);
});
},
methods: {
initMenu(){
let routes = this.$store.state.routes[1].children
let menus = []
this.defaultInfoMenu.map(e => {
routes.map(n => {
e.index == n.path && menus.push(e)
})
})
this.menuList.info = menus
}
}
};
</script>
<style lang="scss" scoped>
.sidebar{
z-index: 2;
position: fixed;
top: 120px;
left: 0;
bottom: 20px;
right: 0;
width: 210px !important;
&.noNav{
top: 80px;
}
}
.sidebar::-webkit-scrollbar {
width: 0;
}
.sidebar-el-menu:not(.el-menu--collapse) {
width: 100%;
}
.sidebar > ul {
height: 100%;
}
</style>

@ -0,0 +1,185 @@
<template>
<div class="tags" v-if="showTags">
<ul>
<li class="tags-li" v-for="(item,index) in tagsList" :class="{'active': isActive(item.path)}" :key="index">
<router-link :to="item.path" class="tags-li-title">
{{item.title}}
</router-link>
<span class="tags-li-icon" @click="closeTags(index)"><i class="el-icon-close"></i></span>
</li>
</ul>
<div class="tags-close-box">
<el-dropdown @command="handleTags">
<el-button size="mini" type="primary">
标签选项<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu size="small" slot="dropdown">
<el-dropdown-item command="other">关闭其他</el-dropdown-item>
<el-dropdown-item command="all">关闭所有</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import bus from '@/libs/bus';
export default {
data() {
return {
tagsList: []
}
},
methods: {
isActive(path) {
return path === this.$route.fullPath;
},
//
closeTags(index) {
const delItem = this.tagsList.splice(index, 1)[0];
const item = this.tagsList[index] ? this.tagsList[index] : this.tagsList[index - 1];
if (item) {
delItem.path === this.$route.fullPath && this.$router.push(item.path);
}else{
this.$router.push('/dashboard');
}
},
//
closeAll(){
this.tagsList = [];
this.$router.push('/dashboard');
},
//
closeOther(){
const curItem = this.tagsList.filter(item => {
return item.path === this.$route.fullPath;
})
this.tagsList = curItem;
},
//
setTags(route){
const isExist = this.tagsList.some(item => {
return item.path === route.fullPath;
})
if(!isExist){
if(this.tagsList.length >= 8){
this.tagsList.shift();
}
this.tagsList.push({
title: route.meta.title,
path: route.fullPath,
name: route.matched[1].components.default.name
})
}
bus.$emit('tags', this.tagsList);
},
handleTags(command){
command === 'other' ? this.closeOther() : this.closeAll();
}
},
computed: {
showTags() {
return this.tagsList.length > 0;
}
},
watch:{
$route(newValue, oldValue){
this.setTags(newValue);
}
},
created(){
this.setTags(this.$route);
//
bus.$on('close_current_tags', () => {
for (let i = 0, len = this.tagsList.length; i < len; i++) {
const item = this.tagsList[i];
if(item.path === this.$route.fullPath){
if(i < len - 1){
this.$router.push(this.tagsList[i+1].path);
}else if(i > 0){
this.$router.push(this.tagsList[i-1].path);
}else{
this.$router.push('/');
}
this.tagsList.splice(i, 1);
break;
}
}
})
}
}
</script>
<style lang="scss" scoped>
.tags {
position: relative;
height: 30px;
overflow: hidden;
background: #fff;
padding-right: 120px;
box-shadow: 0 5px 10px #ddd;
}
.tags ul {
box-sizing: border-box;
width: 100%;
height: 100%;
}
.tags-li {
float: left;
margin: 3px 5px 2px 3px;
border-radius: 3px;
font-size: 12px;
overflow: hidden;
cursor: pointer;
height: 23px;
line-height: 23px;
border: 1px solid #e9eaec;
background: #fff;
padding: 0 5px 0 12px;
vertical-align: middle;
color: #666;
-webkit-transition: all .3s ease-in;
-moz-transition: all .3s ease-in;
transition: all .3s ease-in;
}
.tags-li:not(.active):hover {
background: #f8f8f8;
}
.tags-li.active {
color: #fff;
}
.tags-li-title {
float: left;
max-width: 80px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-right: 5px;
color: #666;
}
.tags-li.active .tags-li-title {
color: #fff;
}
.tags-close-box {
position: absolute;
right: 0;
top: 0;
box-sizing: border-box;
padding-top: 1px;
text-align: center;
width: 110px;
height: 30px;
background: #fff;
box-shadow: -3px 0 15px 3px rgba(0, 0, 0, .1);
z-index: 10;
}
</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.component ? result.push(`${e.component}:${n.name}:${j.name}`) : result.push(`${n.component}:${j.name}`))
})
}else{
result.push(`${e.component}:${n.name}`)
}
}
})
}
})
store.commit('addBtnPerData',{btnPermissions: result})
}

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

@ -0,0 +1,234 @@
import { Message } from 'element-ui'
const pad2 = str => ('0' + str).substr(-2)
function fMoney (s, n) {
n = n > 0 && n <= 20 ? n : 2
s = parseFloat((s + '').replace(/[^\d\.-]/g, '')).toFixed(n) + ''
let l = s.split('.')[0].split('').reverse()
let r = s.split('.')[1]
let t = ''
for(let i = 0; i < l.length; i ++ ) {
t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? ',' : '')
}
return t.split('').reverse().join('') + '.' + r
}
/**
* @description 判断列表1中是否包含了列表2中的某一项
* 因为用户权限 access 为数组includes 方法无法直接得出结论
* */
function includeArray (list1, list2) {
let status = false;
list2.forEach(item => {
if (list1.includes(item)) status = true;
});
return status;
}
function toDateTime (date, time) {
if (!date) return ''
date = date.toString()
time = time ? time.toString() : ''
let str = `${date.substr(0, 4)}-${date.substr(4, 2)}-${date.substr(6, 2)}`
if (date.length == 14) {
str += ` ${date.substr(8, 2)}:${date.substr(10, 2)}:${date.substr(12, 2)}`
} else if (date.length == 6) {
str = `${date.substr(0, 2)}:${date.substr(2, 2)}:${date.substr(4, 2)}`
} else if (time) {
str += ` ${time.substr(0, 2)}:${time.substr(2, 2)}:${time.substr(4, 2)}`
}
return str
}
function Percentage(num, total) {
if (num == 0 || total == 0){
return 0;
}
return (Math.round(num / total * 10000) / 100.00);// 小数点后两位百分比
}
function fMoney2 (m) {
return parseFloat(m).toFixed(2)
}
function systemStatus (sts) {
const status = {
'1': '运行中',
'2': '故障中'
}
return status[sts] || '未知状态'
}
function systemTypeStatus (sts) {
const status = {
'1': '工具',
'2': '实训',
'3': '网站'
}
return status[sts] || '未知状态'
}
function systemAttributionStatus (sts) {
const status = {
'1': '外部产品',
'2': '内部系统'
}
return status[sts] || '未知状态'
}
function courseTypeStatus (sts) {
const status = {
'1': '实训课程',
'2': '理论课程'
}
return status[sts] || '未知状态'
}
function hoursStatus (sts) {
const status = {
'1': '32课时',
'2': '64课时'
}
return status[sts] || '未知状态'
}
function roleStatus (sts) {
const status = {
'1': '超级管理员',
'2': '管理员',
'3': '老师',
'4': '学生'
}
return status[sts] || '未知状态'
}
function orderTypeFn (sts) {
const status = {
'1': '正式',
'2': '试用'
}
return status[sts] || '未知状态'
}
function orderStatusFn (sts) {
const status = {
'1': '待发货',
'2': '已完成',
'3': '已取消'
}
return status[sts] || '未知状态'
}
function orderNatureFn (sts) {
const status = {
'1': '初签',
'2': '续签'
}
return status[sts] || '未知状态'
}
// 获取出生日期
function 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;
}
// 获取性别
function getSex(idCard) {
var sexStr = '';
if (parseInt(idCard.slice(-2, -1)) % 2 == 1) {
sexStr = 'man';
}
else {
sexStr = 'woman';
}
return sexStr;
}
function removeByValue(arr, val) {
for(var i=0; i<arr.length; i++) {
if(arr[i] == val) {
arr.splice(i, 1);
break;
}
}
}
//返回格式化时间,传参例如:"yyyy-MM-dd hh:mm:ss"
function 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;
}
// 是否IE
function isIE() {
if (!!window.ActiveXObject || "ActiveXObject" in window) return true
return false
}
// 成功提示
function successMsg(message) {
Message.success({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration: 1500})
}
// 警告提示
function warningMsg(message) {
Message.warning({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration: 1500})
}
// 错误提示
function errorMsg(message) {
Message.error({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration: 1500})
}
export {
fMoney,
toDateTime,
Percentage,
fMoney2,
systemStatus,
systemTypeStatus,
systemAttributionStatus,
courseTypeStatus,
hoursStatus,
roleStatus,
orderTypeFn,
orderStatusFn,
orderNatureFn,
getBirth,
getSex,
removeByValue,
formatDate,
isIE,
successMsg,
warningMsg,
errorMsg
}

@ -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,41 @@
import store from '@/store';
import router from '@/router';
import generateBtnPermission from '../auth/generateBtnPermission';
const infoSidebar = ['information','content']
const matchSidebar = ['matchintro','matchprogress','matchsignup']
const newRoutes = []
function createMeta(item){
let meta = { title: item.name }
infoSidebar.includes(item.component) && (meta.sidebar = 'info')
matchSidebar.includes(item.component) && (meta.sidebar = 'match')
return meta
}
function createRoute(data){
data.map(e => {
if(e.select && e.component){
let meta = createMeta(e)
newRoutes.push({
name: e.component,
path: e.component,
component: () => import(`@/pages/${e.component}.vue`),
meta
})
}
e.children && e.children.length && createRoute(e.children)
})
}
export default function(data,path){
generateBtnPermission(data)
createRoute(data)
let routes = router.options.routes
routes[1].children = [...routes[1].children,...newRoutes]
store.commit("addRoutesData", { routes })
router.addRoutes(routes)
setTimeout(() => {
!newRoutes.find(n => n.name == 'dashboard') && router.push(newRoutes[0].path)
},10)
}

@ -0,0 +1,25 @@
import store from '@/store';
import router from '@/router';
export default function(){
setTimeout(() => {
let routes = store.state.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,58 @@
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 { messages } from '@/i18n';
import 'babel-polyfill';
import '@/libs/resize';
import api from '@/api';
import store from '@/store'
import {post,get,del,put} from '@/plugins/requests/index.js';
import { systemStatus, systemTypeStatus, systemAttributionStatus, courseTypeStatus, hoursStatus, roleStatus, orderTypeFn, orderStatusFn, orderNatureFn, Percentage, removeByValue, formatDate, isIE, successMsg, warningMsg, errorMsg } from './libs/core';
import permission from '@/router/permission';
import Setting from '@/setting';
// 插件
import plugins from '@/plugins';
Vue.use(plugins);
Vue.prototype.api = api;
Vue.prototype.$get = get;
Vue.prototype.$post = post;
Vue.prototype.$del = del;
Vue.prototype.$put = put;
Vue.prototype.systemStatus = systemStatus;
Vue.prototype.systemTypeStatus = systemTypeStatus;
Vue.prototype.systemAttributionStatus = systemAttributionStatus;
Vue.prototype.courseTypeStatus = courseTypeStatus;
Vue.prototype.hoursStatus = hoursStatus;
Vue.prototype.roleStatus = roleStatus;
Vue.prototype.orderTypeFn = orderTypeFn;
Vue.prototype.orderStatusFn = orderStatusFn;
Vue.prototype.orderNatureFn = orderNatureFn;
Vue.prototype.Percentage = Percentage;
Vue.prototype.removeByValue = removeByValue;
Vue.prototype.formatDate = formatDate;
Vue.prototype.isIE = isIE;
Vue.prototype.successMsg = successMsg;
Vue.prototype.warningMsg = warningMsg;
Vue.prototype.errorMsg = errorMsg;
Vue.config.productionTip = false;
Vue.use(VueI18n);
Vue.use(ElementUI);
const i18n = new VueI18n({
locale: Setting.i18n.default,
messages
});
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount('#app');

@ -0,0 +1,56 @@
<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">返回首页</el-button>
</router-link>
<el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
</div>
</div>
</template>
<script>
export default {
methods: {
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,56 @@
<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">返回首页</el-button>
</router-link>
<el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
</div>
</div>
</template>
<script>
export default {
methods: {
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,250 @@
<template>
<div>
<breadcrumb :data="'课程资源管理/课程信息'" :route="'course'"></breadcrumb>
<div class="page">
<div class="p-title">课程信息</div>
<div class="page-content">
<el-form :disabled="isDetail" label-width="80px" label-suffix=":" size="small">
<el-form-item label="课程名称">
<div class="d-inline-block">
<el-input placeholder="请输入课程名称" v-model="name" clearable maxlength="25"></el-input>
</div>
</el-form-item>
<el-form-item label="课程分类">
<div class="d-inline-block">
<el-select v-model="classificationId" placeholder="请选择课程分类">
<el-option v-for="item in classificationList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</el-form-item>
<el-form-item label="课程封面">
<el-upload class="avatar-uploader" accept=".jpg,.png,.jpeg" :on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" :limit="1" :on-exceed="handleExceed" :action="this.api.fileupload" name="file">
<img v-if="coverUrl" :src="coverUrl" class="avatar">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip" class="el-upload__tip">
<p>只能上传jpg/png文件</p>
<p>课程封面图将按2:1显示最佳分辨率1400*700</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="课程介绍">
<quill :border="true" :readonly="isDetail" v-model="description" :height="400" />
</el-form-item>
<el-form-item>
<el-button type="primary" size="small" v-throttle @click="save" v-show="!isDetail">{{id ? '更新' : '创建'}}</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import quill from '@/components/quill'
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
schoolId: this.$store.state.schoolId,
id: '',
isDetail: Boolean(this.$route.query.show),
userId: this.$store.state.userLoginId,
username: this.$store.state.name,
classificationId: '',
coverUrl: '',
name: '',
classificationList: [],
uploadList: [],
description: '',
submiting: false
};
},
mounted() {
this.id = this.$route.query.id
this.getClassification()
this.id && this.getData()
},
components: {
quill,
breadcrumb
},
methods: {
save() {
if(this.submiting) return false
if(!this.name) return this.warningMsg('请填写课程名称')
if(!this.classificationId) return this.warningMsg('请选择课程分类')
if(!this.coverUrl) return this.warningMsg('请上传课程封面')
this.submiting = true
let data = {
id: this.id,
classificationId: this.classificationId,
coverUrl: this.coverUrl,
description: this.description,
name: this.name,
founderId: this.userId,
schoolId: this.schoolId,
founderName: this.username,
distinguish: 1
}
if(this.id){
this.$put(this.api.editCourse, data).then(res => {
this.submiting = false
this.successMsg('修改成功');
this.$router.back()
})
.catch(err => {
this.submiting = false
});
}else{
this.$post(this.api.addCourse, data).then(res => {
this.submiting = false
this.$confirm('课程创建成功,是否马上进行课程内容设置?', '提示', {
type: 'success',
confirmButtonText: '马上设置',
cancelButtonText: '稍后操作',
})
.then(() => {
this.$router.push(`courseConfig?id=${res.data.courseId}`)
}).catch(() => {
this.$router.back()
});
})
.catch(err => {
this.submiting = false
});
}
},
getClassification() {
this.$get(this.api.queryAllClassification).then(res => {
this.classificationList = res.data.classificationList
}).catch(res => {});
},
getData() {
this.$get(`${this.api.getCourse}/${this.id}`)
.then(res => {
let data = res.data.course
this.name = data.name
this.classificationId = data.classificationId
this.description = data.description
this.coverUrl = data.coverUrl
this.uploadList.push({
name: 'cover.jpg',
url: this.coverUrl
})
})
.catch(err => {
});
},
//
handleExceed(files, fileList) {
this.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
this.coverUrl = res.data.filesResult.fileUrl
// this.uploadList.push({ name: file.name, url: response.message.fileUrl });
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
let fileName = this.coverUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {
this.coverUrl = ''
}).catch(res => {})
},
uploadSure(){
this.importVisible = false
this.pageNo = 1
this.staffGradeId = ''
this.keyword = ''
this.getTeacher()
},
goback() {
if(this.isDetail){
this.$router.back()
}else{
this.$confirm('确定返回?未更新的信息将不会保存。', '提示', {
type: 'warning'
})
.then(() => {
this.$router.back()
})
.catch(() => {});
}
},
},
};
</script>
<style lang="scss" scoped>
$avatar-width: 104px;
/deep/.avatar-uploader{
.el-upload {
position: relative;
width: $avatar-width;
border: 1px dashed #d9d9d9;
border-radius: 2px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #409EFF;
}
.uploader-default{
display: flex;
flex-direction: column;
justify-content: center;
width: $avatar-width !important;
height: $avatar-width;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i{
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p{
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
.avatar {
width: $avatar-width;
height: $avatar-width;
display: block;
}
}
.el-upload__tip{
margin-top: 0;
p{
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child{
margin-bottom: 5px;
}
}
}
}
/deep/.d-inline-block{
width: 216px;
.el-select,.el-input{
width: 100%;
}
}
</style>

@ -0,0 +1,248 @@
<template>
<div>
<breadcrumb :data="'官方资讯管理/添加内容'" :route="'information'"></breadcrumb>
<div class="page">
<div class="p-title">添加内容</div>
<div class="page-content">
<el-form label-width="90px" label-suffix=":" size="small">
<el-form-item label="封面图">
<el-upload class="avatar-uploader" accept=".jpg,.png,.jpeg" :on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" :limit="1" :on-exceed="handleExceed" :action="this.api.fileupload" name="file">
<img v-if="coverUrl" :src="coverUrl" class="avatar">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="作者">
<div class="d-inline-block">
<el-input placeholder="请输入作者" v-model="author" clearable></el-input>
</div>
</el-form-item>
<el-form-item label="日期">
<div class="d-inline-block">
<el-date-picker v-model="date" type="date" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
</div>
</el-form-item>
<el-form-item label="文章标题">
<el-input placeholder="请输入文章标题" v-model="title" clearable></el-input>
</el-form-item>
<el-form-item label="文章内容">
<quill :border="true" v-model="content" :uploading.sync="uploading" :height="400" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-throttle @click="saveData">确定</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import quill from '@/components/quill'
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
columnId: this.$route.query.columnId,
sort: this.$route.query.sort,
id: '',
userId: this.$store.state.userLoginId,
coverUrl: '',
uploadList: [],
uploadDataList: [],
author: '',
date: '',
title: '',
content: '',
submiting: false,
uploading: false
};
},
components: {
quill,
breadcrumb
},
mounted() {
this.id = this.$route.query.id
this.id && this.getData()
},
methods: {
getData() {
this.$get(`${this.api.getArticle}/${this.id}`)
.then(res => {
let data = res.data.article
this.coverUrl = data.coverUrl
this.author = data.author
this.date = data.date
this.title = data.title
this.content = data.content
})
.catch(err => {
});
},
saveData() {
if(this.submiting) return false
if(!this.coverUrl) return this.warningMsg('请上传封面图')
if(!this.author) return this.warningMsg('请填写作者')
if(!this.date) return this.warningMsg('请选择日期')
if(!this.title) return this.warningMsg('请填写文章标题')
if(!this.content) return this.warningMsg('请填写文章内容')
if(this.uploading) return this.warningMsg('图片正在上传中,请稍等')
this.submiting = true
let data = {
id: this.id,
columnId: this.columnId,
author: this.author,
coverUrl: this.coverUrl,
date: this.date,
title: this.title,
content: this.content,
sort: this.sort
}
if(this.id){
this.$put(this.api.editArticle, data).then(res => {
this.submiting = false
this.successMsg('修改成功');
this.back()
})
.catch(err => {
this.submiting = false
})
}else{
this.$post(this.api.addArticle, data).then(res => {
this.submiting = false
this.successMsg('创建成功');
this.back()
})
.catch(err => {
this.submiting = false
})
}
},
handleCurrentChange(val) {
this.currPage = val;
},
handleExceed(files, fileList) {
this.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
if(this.coverUrl){
let fileName = this.coverUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {}).catch(res => {});
}
this.coverUrl = res.data.filesResult.fileUrl
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
let fileName = this.coverUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {
this.coverUrl = ''
}).catch(res => {});
},
uploadSure(){
this.BatchUpload = false
this.pageNo = 1
this.keyword = ''
this.getData()
},
back(){
// this.$router.push(`/content?id=${this.columnId}`)
this.$router.back()
},
goback() {
this.$confirm('确定返回?未更新的信息将不会保存。', '提示', {
type: 'warning'
})
.then(() => {
this.back()
})
.catch(() => {});
},
addSponsor(){
this.sponsorList.push('')
},
delSponsor(index){
this.sponsorList.splice(index,1)
},
addOrganizer(){
this.organzinerList.push('')
},
delOrganizer(index){
this.organzinerList.splice(index,1)
},
},
};
</script>
<style lang="scss" scoped>
$avatar-width: 104px;
/deep/.avatar-uploader{
.el-upload {
position: relative;
width: $avatar-width;
border: 1px dashed #d9d9d9;
border-radius: 2px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #409EFF;
}
.uploader-default{
display: flex;
flex-direction: column;
justify-content: center;
width: $avatar-width !important;
height: $avatar-width;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i{
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p{
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
.avatar {
width: $avatar-width;
height: $avatar-width;
display: block;
}
}
.el-upload__tip{
margin-top: 0;
p{
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child{
margin-bottom: 5px;
}
}
}
}
/deep/.d-inline-block{
width: 216px;
.el-select,.el-input{
width: 100%;
}
}
</style>

@ -0,0 +1,504 @@
<template>
<div>
<breadcrumb :data="'学校信息列表/学校信息'" :route="'dashboard'"></breadcrumb>
<div class="page m-b-20">
<div class="p-title">学校信息</div>
<div class="page-content">
<ul class="list" v-if="isDetail">
<li>
<div class="side">
<span class="name"><i class="required">*</i>国家</span>
<span class="val">中国</span>
</div>
<div class="side">
<span class="name"><i class="required">*</i>客户类型</span>
<span class="val">{{clientTypeList.find(n => n.value == form.type).name}}</span>
</div>
</li>
<li>
<div class="side">
<span class="name"><i class="required">*</i>省份</span>
<span class="val">{{provinceList.find(n => n.provinceId == form.provinceId).provinceName}}</span>
</div>
<div class="side">
<span class="name"><i class="required">*</i>城市</span>
<span class="val">{{cityList.find(n => n.cityId == form.cityId).cityName}}</span>
</div>
</li>
<li>
<div class="side">
<span class="name"><i class="required">*</i>客户名称</span>
<span class="val">{{form.clientName}}</span>
</div>
<div class="side">
<span class="name"><i class="required">*</i>联系人名称</span>
<span class="val">{{form.contactPersonName}}</span>
</div>
</li>
<li>
<div class="side">
<span class="name"><i class="required">*</i>手机号</span>
<span class="val">{{form.phone}}</span>
</div>
<div class="side"></div>
</li>
</ul>
<el-form v-else :model="form" :rules="rules" ref="form" label-width="100px" size="small">
<el-form-item prop="countries" label="国家">
<div class="d-inline-block">
<el-select v-model="form.countries" placeholder="请选择国家">
<el-option v-for="(item,index) in countryList" :key="index" :label="item.name" :value="item.name"></el-option>
</el-select>
</div>
</el-form-item>
<el-form-item prop="provinceId" label="省份">
<div class="d-inline-block">
<el-select v-model="form.provinceId" placeholder="" @change="getCity()" @clear="clearprovince()">
<el-option v-for="(item,index) in provinceList" :key="index" :label="item.provinceName" :value="item.provinceId"></el-option>
</el-select>
</div>
</el-form-item>
<el-form-item prop="clientName" label="客户名称">
<div class="d-inline-block">
<el-input placeholder="请输入客户名称" v-model="form.clientName" @change="nameChange"></el-input>
</div>
</el-form-item>
<el-form-item prop="phone" label="手机号">
<div class="d-inline-block">
<el-input placeholder="请输入手机号" v-model="form.phone" maxlength="11"></el-input>
</div>
</el-form-item>
<el-form-item prop="type" label="客户类型">
<div class="d-inline-block">
<el-select v-model="form.type" placeholder="">
<el-option v-for="(item,index) in clientTypeList" :key="index" :label="item.name" :value="item.value"></el-option>
</el-select>
</div>
</el-form-item>
<el-form-item prop="cityId" label="城市">
<div class="d-inline-block">
<el-select v-model="form.cityId" :disabled="form.provinceId ? false : true" placeholder="">
<el-option v-for="(item,index) in cityList" :key="index" :label="item.cityName" :value="item.cityId"></el-option>
</el-select>
</div>
</el-form-item>
<el-form-item prop="contactPersonName" label="联系人名称">
<div class="d-inline-block">
<el-input placeholder="请输入联系人名称" v-model="form.contactPersonName"></el-input>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" size="small" v-if="!isDetail" v-throttle @click="saveAdd">确定</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="page" v-if="id">
<div class="p-title">课程权限</div>
<div class="page-content">
<div class="tool" v-if="!isDetail">
<ul class="filter"></ul>
<div>
<el-button type="primary" size="small" @click="addCourse">添加课程</el-button>
</div>
</div>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" row-key="id">
<el-table-column v-if="!isDetail" type="selection" width="80" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="name" label="课程名称">
</el-table-column>
<el-table-column prop="gmtCreate" 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.chapterNum ? scope.row.chapterNum : 0}}({{scope.row.subsectionNum ? scope.row.subsectionNum : 0}}小节)
</template>
</el-table-column>
<el-table-column prop="classification" label="课程分类">
</el-table-column>
<el-table-column label="操作" align="center" width="300" v-if="!isDetail">
<template slot-scope="scope">
<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="totals" @current-change="handleCurrentChange" :current-page="pageNo">
</el-pagination>
</div>
</div>
</div>
<el-dialog title="添加课程" :visible.sync="addVisible" width="50%" @close="closeAdd" :close-on-click-modal="false">
<div class="search">
<label>搜索</label>
<el-input placeholder="请输入课程名称/课程分类" prefix-icon="el-icon-search" v-model="keyword" size="small" clearable></el-input>
</div>
<el-table
:data="coursesData"
ref="courseTable"
row-key="id"
class="table"
stripe
header-align="center"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="80" align="center" :reserve-selection="true" :selectable="disabledSelection"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center">
<template
slot-scope="scope"
>{{scope.$index + (pageCourse - 1) * pageSizeCourse + 1}}</template>
</el-table-column>
<el-table-column prop="name" label="课程名称"></el-table-column>
<el-table-column prop="founder" label="创建人" width="100" align="center"></el-table-column>
<el-table-column label="章节数" width="110" align="center">
<template slot-scope="scope">
{{scope.row.chapterNum ? scope.row.chapterNum : 0}}({{scope.row.subsectionNum ? scope.row.subsectionNum : 0}}小节)
</template>
</el-table-column>
<el-table-column prop="classification" label="课程分类"></el-table-column>
</el-table>
<div class="pagination">
<el-pagination
background
@current-change="handleCourseCurrentChange"
:current-page="pageCourse"
:page-size="pageSizeCourse"
layout="total,prev, pager, next"
:total="totalCourse"
></el-pagination>
</div>
<div class="tag-group">
<span class="tag-group__title">已选择</span>
<el-tag
class="course-name"
v-for="item in multipleSelection"
:key="item.id"
type="danger"
closable
@close="removeCourse(item)">
{{ item.name }}
</el-tag>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="addVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="saveCourse">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import breadcrumb from '@/components/breadcrumb'
export default {
name: 'addcustomer',
data() {
return {
id: this.$route.query.id,
isDetail: Boolean(this.$route.query.show),
schoolId: this.$store.state.schoolId,
form: {
countries: '中国',
clientName: '',
provinceId: '',
contactPersonName: '',
phone: '',
cityId: '',
type: 1,
},
rules: {
type: [
{ required: true, message: '请选择客户类型', trigger: 'change' }
],
countries: [
{ required: true, message: '请选择国家', trigger: 'change' }
],
provinceId: [
{ required: true, message: '请选择省份', trigger: 'change' }
],
cityId: [
{ required: true, message: '请选择城市', trigger: 'change' }
],
contactPersonName: [
{ required: true, message: '请输入管理员姓名', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{
pattern: /^1[3456789]\d{9}$/,
message: '请输入正确的手机号',
trigger: 'blur'
}
],
clientName: [
{ required: true, message: '请输入客户名称', trigger: 'blur' }
],
},
clientTypeList: [{
name: '正式',
value: 1
},
{
name: '试用',
value: 2
},
{
name: '到期',
value: 3
}],
countryList: [{
name:'中国'
}],
provinceList: this.$store.state.provinceList,
cityList: [],
originalName: '',
nameRepeat: false,
keyword: '',
searchTimer: null,
listData: [],
multipleSelection: [],
pageNo: 1,
pageSize: 10,
totals: 0,
addVisible: false,
coursesData: [],
pageCourse: 1,
pageSizeCourse: 10,
totalCourse: 0,
submiting: false
};
},
components: {
breadcrumb
},
mounted() {
if(this.id){
this.getData()
this.getCourses()
}
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
methods: {
getData(){
this.$get(`${this.api.getClient}/${this.id}`).then((res) => {
this.form = res.data.client
this.originalName = res.data.client.clientName
this.form.countries = '中国'
this.getCityData()
}).catch((res) => {
})
},
getCourses(){
this.$get(`${this.api.queryBuiltInCourseByCondition}/${this.pageNo}?schoolId=${this.id}`).then((res) => {
this.listData = res.data.courseList
this.totals = res.data.total
}).catch((res) => {})
},
nameChange(){
if(this.form.clientName !== this.originalName){
this.$get(`${this.api.getClientName}?clientName=${this.form.clientName}`).then(res => {
if(res.data.client.length){
this.nameRepeat = true
this.warningMsg('该客户名称已存在')
}else{
this.nameRepeat = false
}
}).catch(res => {});
}else{
this.nameRepeat = false
}
},
//
clearprovince(){
this.form.cityId = ''
},
getCity(){
this.clearprovince()
this.getCityData()
this.pageNo = 1
},
getCityData(){
let data = {
provinceId: this.form.provinceId
}
this.$get(this.api.queryCity,data).then(res => {
this.cityList = res.data.list
}).catch(res => {});
},
saveAdd(){
if(this.submiting) return false
this.$refs.form.validate((valid) => {
if (valid) {
if(this.nameRepeat) return this.warningMsg('该客户名称已存在')
this.form.provinceName = this.provinceList.find(n => n.provinceId == this.form.provinceId).provinceName
this.form.cityName = this.cityList.find(n => n.cityId == this.form.cityId).cityName
let data = this.form
this.submiting = true
if(this.id){
this.$post(this.api.updateClient,data).then((res) => {
this.submiting = false
this.successMsg('编辑成功')
this.$router.back()
}).catch((res) => {
this.submiting = false
})
}else{
this.$post(this.api.addClient,data).then((res) => {
this.submiting = false
this.successMsg('添加成功')
this.$router.back()
}).catch((res) => {
this.submiting = false
})
}
}
})
},
goback() {
if(this.isDetail){
this.$router.back()
}else{
this.$confirm('确定返回?未更新的信息将不会保存。', '提示', {
type: 'warning'
})
.then(() => {
this.$router.back()
})
.catch(() => {})
}
},
handleSelectionChange(val) {
this.multipleSelection = val
},
handleCurrentChange(val) {
this.pageNo = val
this.getCourses()
},
handleDelete(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteBuiltInCourse}?courseId=${row.id}&schoolId=${this.id}&classificationId=${row.classificationId}`).then(res => {
this.successMsg('删除成功')
this.getCourses()
}).catch(res => {});
})
.catch(() => {});
},
addCourse(){
this.addVisible = true
this.getAddCourses()
},
closeAdd(){
this.keyword = ''
this.pageCourse = 1
this.$refs.courseTable.clearSelection()
},
getAddCourses(){
let data = {
classificationId: '',
name: this.keyword,
}
this.$get(`${this.api.queryCourseByCondition}/${this.pageCourse}`,data).then(res => {
this.coursesData = res.data.courseList
this.totalCourse = res.data.total
}).catch(res => {})
},
initData(){
this.pageCourse = 1
this.getAddCourses()
},
handleCourseCurrentChange(val){
this.pageCourse = val
this.getAddCourses()
},
disabledSelection(row,index){
let listData = this.listData
if(listData.find(n => n.id == row.id)) return false
return true
},
removeCourse(item){
this.multipleSelection.splice(this.coursesData.findIndex(n => n.id == item.id),1)
this.$refs.courseTable.toggleRowSelection(item)
},
saveCourse(){
if(!this.multipleSelection.length) return this.errorMsg('请选择课程')
let ids = this.multipleSelection.map(n => n.id).join(',')
let classificationIds = Array.from(new Set(this.multipleSelection.map(n => n.classificationId))).join(',')
this.$post(`${this.api.addBuiltInCourse}?schoolId=${this.id}&courseIds=${ids}&classificationIds=${classificationIds}`).then(res => {
this.successMsg('添加成功')
this.addVisible = false
this.getCourses()
}).catch(res => {})
}
}
};
</script>
<style lang="scss" scoped>
.search{
display: flex;
align-items: center;
margin-bottom: 20px;
label{
white-space: nowrap;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
}
.el-input{
width: 250px;
}
}
/deep/.d-inline-block{
width: 216px;
.el-select,.el-input{
width: 100%;
}
}
.course-name{
margin-right: 5px;
}
.list{
li{
display: flex;
justify-content: center;
align-items: center;
margin: 32px 0;
.side{
width: 200px;
&:first-child{
margin-right: 100px;
}
}
.name,.val{
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
}
.name{
width: 45%;
text-align: right;
}
.val{
width: 55%;
}
}
}
</style>

@ -0,0 +1,411 @@
<template>
<div>
<breadcrumb :data="'赛事信息管理/创建赛事'" :route="'match'"></breadcrumb>
<div class="page">
<div class="p-title">创建赛事</div>
<div class="page-content">
<el-form label-width="170px" label-suffix=":" size="small">
<el-form-item label="竞赛封面(选填)">
<el-upload class="avatar-uploader" accept=".jpg,.png,.jpeg,.gif" :on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" :limit="1" :on-exceed="handleExceed" :action="this.api.fileupload" name="file" >
<img v-if="coverUrl" :src="coverUrl" class="avatar">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip" class="el-upload__tip">
<p>展示宽度为220高度140JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="竞赛封面长图(选填)">
<el-upload class="avatar-uploader avatar-uploader-lg" accept=".jpg,.png,.jpeg,.gif" :on-remove="handleLgRemove" :on-error="uploadError" :on-success="uploadLgSuccess" :before-remove="beforeRemove" :limit="1" :on-exceed="handleExceed" :action="this.api.fileupload" name="file">
<img v-if="carouselUrl" :src="carouselUrl" class="avatar-lg">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip" class="el-upload__tip">
<p>展示宽度为1920高度300JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="竞赛名称">
<div class="d-inline-block">
<el-input placeholder="请输入竞赛名称" v-model="name" clearable></el-input>
</div>
</el-form-item>
<el-form-item label="主办方">
<div class="inline-input">
<div class="input-wrap" v-for="(item,index) in sponsorList" :key="index">
<el-input placeholder="主办方名称" v-model="sponsorList[index]"></el-input>
<i v-if="sponsorList.length > 1" class="remove" @click="delSponsor(index)"></i>
<button v-if="index == 0" class="add-btn" @click="addSponsor">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</div>
</div>
</el-form-item>
<el-form-item label="承办方(选填)">
<div class="inline-input">
<div class="input-wrap" v-for="(item,index) in undertakerList" :key="index">
<el-input placeholder="承办方名称" v-model="undertakerList[index]"></el-input>
<i v-if="undertakerList.length > 1" class="remove" @click="delOrganizer(index)"></i>
<button v-if="index == 0" class="add-btn" @click="addOrganizer">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</div>
</div>
<button v-if="!undertakerList.length" class="add-btn" @click="addOrganizer">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</el-form-item>
<el-form-item label="报名时间">
<el-date-picker v-model="signupTime" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="pickerOptions"></el-date-picker>
</el-form-item>
<el-form-item label="竞赛时间">
<el-date-picker v-model="playTime" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="pickerOptions"></el-date-picker>
</el-form-item>
<el-form-item label="竞赛详情">
<quill :border="true" v-model="description" :height="400" />
</el-form-item>
<el-form-item>
<el-button size="small" v-throttle @click="save(1)">保存</el-button>
<el-button type="primary" size="small" v-throttle @click="save(0)">发布</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import quill from '@/components/quill'
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
id: '',
coverUrl: '',
carouselUrl: '',
publishStatus: 0,
userId: this.$store.state.userLoginId,
username: this.$store.state.name,
uploadList: [],
uploadDataList: [],
coverVisible: false,
coverImageUrl: '',
name: '',
sponsor: '',
sponsorList: [''],
undertaker: '',
undertakerList: [''],
signUpStartTime: '',
signUpEndTime: '',
signupTime: '',
playTime: '',
playStartTime: '',
playEndTime: '',
description: '',
pickerOptions: {
disabledDate: time => {
return time.getTime() < new Date().getTime() - 86400000
}
},
submiting: false
};
},
components: {
quill,
breadcrumb
},
watch: {
signupTime: function(val){
if(val){
this.signUpStartTime = val[0]
this.signUpEndTime = val[1]
}else{
this.signUpStartTime = ''
this.signUpEndTime = ''
}
},
playTime: function(val){
if(val){
this.playStartTime = val[0]
this.playEndTime = val[1]
}else{
this.playStartTime = ''
this.playEndTime = ''
}
}
},
mounted() {
this.id = this.$route.query.id
this.isDetail = Boolean(this.$route.query.show)
this.id && this.getData()
},
methods: {
save(status) {
if(this.submiting) return false
this.sponsor = this.sponsorList.filter(d=>d).join()
this.undertaker = this.undertakerList.filter(d=>d).join()
if(!this.name) return this.warningMsg('请填写竞赛名称')
if(status == 0){
if(!this.sponsor) return this.warningMsg('请填写主办方')
if(!this.signUpStartTime) return this.warningMsg('请选择报名时间')
}
let now = new Date().getTime()
let signUpStartTime = new Date(this.signUpStartTime).getTime()
let signUpEndTime = new Date(this.signUpEndTime).getTime()
let playStartTime = new Date(this.playStartTime).getTime()
if(signUpStartTime && now > signUpStartTime) return this.warningMsg('报名时间不能早于当前时间')
if(!this.playStartTime && status == 0) return this.warningMsg('请选择竞赛时间')
if(playStartTime && playStartTime < signUpEndTime) return this.warningMsg('竞赛时间不能早于报名结束时间')
if(!this.description && status == 0) return this.warningMsg('请填写竞赛详情')
let data = {
id: this.id,
coverUrl: this.coverUrl,
carouselUrl: this.carouselUrl,
description: this.description,
founderId: 1,
founderName: this.username,
name: this.name,
playEndTime: this.playEndTime,
playStartTime: this.playStartTime,
publishStatus: status,
signUpEndTime: this.signUpEndTime,
signUpStartTime: this.signUpStartTime,
sponsor: this.sponsor,
undertaker: this.undertaker
}
this.submiting = true
if(this.id){
this.$put(this.api.editContest, data).then(res => {
this.submiting = false
this.successMsg('修改成功');
this.$router.back()
})
.catch(err => {
this.submiting = false
});
}else{
this.$post(this.api.addContest, data).then(res => {
this.submiting = false
this.successMsg('创建成功');
this.$router.back()
})
.catch(err => {
this.submiting = false
});
}
},
getData() {
this.$get(this.api.getContest + this.id)
.then(res => {
if(res.errmessage == 'success'){
let info = res.ExperimentalTeaching
this.coverUrl = info.coverUrl
this.description = info.description
this.name = info.name
this.signupTime = [info.signUpStartTime,info.signUpEndTime]
this.playTime = [info.playStartTime,info.playEndTime]
}else{
this.errorMsg('查询失败');
}
})
.catch(err => {
});
},
handleExceed(files, fileList) {
this.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
if(this.coverUrl){
let fileName = this.coverUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {}).catch(res => {});
}
this.coverUrl = res.data.filesResult.fileUrl
},
uploadLgSuccess(res, file, fileList) {
if(this.carouselUrl){
let fileName = this.carouselUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {}).catch(res => {});
}
this.carouselUrl = res.data.filesResult.fileUrl
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
let fileName = this.coverUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {
this.coverUrl = ''
}).catch(res => {});
},
handleLgRemove(file, fileList) {
let fileName = this.carouselUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {
this.carouselUrl = ''
}).catch(res => {});
},
uploadSure(){
this.BatchUpload = false
this.pageNo = 1
this.keyword = ''
this.getData()
},
goback() {
this.$confirm('确定返回?未更新的信息将不会保存。', '提示', {
type: 'warning'
})
.then(() => {
this.$router.back()
})
.catch(() => {});
},
addSponsor(){
this.sponsorList.push('')
},
delSponsor(index){
this.sponsorList.splice(index,1)
},
addOrganizer(){
this.undertakerList.push('')
},
delOrganizer(index){
this.undertakerList.splice(index,1)
},
},
};
</script>
<style scoped lang="scss">
$upload-width: 220px;
$upload-height: 140px;
$upload-lg-height: 150px;
/deep/.avatar-uploader{
.el-upload {
position: relative;
width: $upload-width;
height: $upload-height;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #cb221c;
}
.uploader-default{
display: flex;
height: $upload-height;
flex-direction: column;
justify-content: center;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i{
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p{
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
}
&.avatar-uploader-lg{
.el-upload {
width: 100%;
max-width: 960px;
height: $upload-lg-height;
.uploader-default{
height: $upload-lg-height;
}
}
}
.avatar {
display: block;
width: $upload-width;
height: $upload-height;
}
.avatar-lg {
display: block;
width: 100%;
height: $upload-lg-height;
}
.el-upload__tip{
margin-top: 0;
p{
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child{
margin-bottom: 5px;
}
}
}
}
/deep/.d-inline-block{
width: 216px;
.el-select,.el-input{
width: 100%;
}
}
.inline-input{
.input-wrap{
display: flex;
align-items: center;
margin-bottom: 10px;
.el-input{
display: inline-block;
width: 216px;
margin-right: 8px;
}
.remove{
width: 16px;
height: 16px;
background: url(../assets/img/close.png) 0 0/cover no-repeat;
cursor: pointer;
}
}
.add-btn{
margin-left: 32px;
}
}
.add-btn{
display: flex;
justify-content: center;
align-items: center;
width: 216px;
line-height: 32px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
background-color: transparent;
border: 1px dashed rgba(0, 0, 0, 0.15);
border-radius: 4px;
cursor: pointer;
i{
margin-right: 8px;
font-size: 14px;
font-weight: bold;
}
}
</style>

@ -0,0 +1,114 @@
<template>
<div>
<breadcrumb :data="'实验系统后台'"></breadcrumb>
<ul class="list">
<li :class="{active: active == 1}" @click="toSystem(1)">
<img src="../assets/img/station1.png" alt="">
<p class="name">运营与管理</p>
<p class="text">电竞赛事运营与管理仿真实训系统</p>
</li>
<li :class="{active: active == 2}" @click="toSystem(2)">
<img src="../assets/img/station2.png" alt="">
<p class="name">编导</p>
<p class="text">电竞赛事编导仿真实训系统</p>
</li>
<li :class="{active: active == 3}" @click="toSystem(3)">
<img src="../assets/img/station3.png" alt="">
<p class="name">主持与解说</p>
<p class="text">电竞赛事主持与解说仿真实训系统</p>
</li>
<li :class="{active: active == 4}" @click="toSystem(4)">
<img src="../assets/img/station4.png" alt="">
<p class="name">数据分析</p>
<p class="text">电竞数据分析仿真实训系统</p>
</li>
<li :class="{active: active == 5}" @click="toSystem(5)">
<img src="../assets/img/station5.png" alt="">
<p class="name">品牌与运营</p>
<p class="text">电竞品牌运营与管理仿真实训系统</p>
</li>
</ul>
</div>
</template>
<script>
import bus from '@/libs/bus'
import breadcrumb from '@/components/breadcrumb'
export default {
name: 'dashboard',
data() {
return {
active: 0
};
},
components: {breadcrumb},
mounted() {
bus.$emit('setBg','backstage')
},
methods: {
toSystem(index){
}
}
};
</script>
<style lang="scss" scoped>
.list{
display: flex;
justify-content: center;
align-items: center;
height: calc(100vh - 165px);
background-color: #fff;
li{
margin: 0 20px;
cursor: pointer;
&:nth-child(even){
margin-top: 200px;
}
.name{
margin: 10px 0 0;
line-height: 1;
font-size: 36px;
color: #000;
font-family: youshe;
}
.text{
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
transition: .2s;
}
img{
max-width: 232px;
border: 3px solid transparent;
transition: .2s;
}
&:hover{
img{
border-color: #CC221C;
}
.name,.text{
color: #CC221C;
}
}
}
}
@media(max-width: 1630px){
.list{
li{
margin: 0 10px;
.name{
font-size: 30px;
}
.text{
font-size: 12px;
}
img{
max-width: 160px;
}
}
}
}
</style>

@ -0,0 +1,156 @@
<template>
<div>
<div class="tool">
<ul class="filter">
</ul>
<div>
<el-button type="primary" size="small" round @click="addClass" v-auth="'course:分类管理:新增'">新增</el-button>
</div>
</div>
<el-table :data="classificationList" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="name" label="课程分类名称">
</el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button type="text" @click="editClass(scope.row)" v-auth="'course:分类管理:修改'">修改</el-button>
<el-divider direction="vertical" v-auth="'course:分类管理:修改'"></el-divider>
<el-button type="text" @click="handleDelete(scope.row)" v-auth="'course:分类管理:删除'">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :title="isAddclass ? '添加分类' : '编辑分类'" :visible.sync="classVisible" width="400px" :close-on-click-modal="false" @close="closeColumn">
<el-form>
<el-form-item>
<el-input placeholder="分类名称" v-model="className"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="classVisible = false"> </el-button>
<el-button size="small" type="primary" @click="classSubmit"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'classification',
data() {
return {
classificationList: [],
multipleSelection: [],
pageNo: 1,
pageSize: 10,
isAddclass: true,
classVisible: false,
curRow: {},
className: ''
};
},
mounted() {
this.getData()
},
methods: {
getData() {
this.$get(this.api.queryAllClassification).then(res => {
this.classificationList = res.data.classificationList
}).catch(res => {});
},
addCourse(){
this.$router.push('/addcourse')
},
editCourse(row){
this.$router.push(`/addcourse?id=${row.id}`)
},
handleDelete(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteClassification}/${row.id}`).then(res => {
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
getRowKeys(row) {
return row.customerId;
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
closeColumn(){
this.className = ''
this.curRow = {}
},
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.join()
this.$del(this.api.deleteClassification,data).then(res => {
this.multipleSelection = [];
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
}).catch(() => {});
}else{
this.errorMsg('请先选择数据 !');
}
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
addClass(){
this.isAddClass = true
this.classVisible = true
},
editClass(row){
this.curRow = row
this.className = row.name
this.isAddClass = false
this.classVisible = true
},
classSubmit(){
if(!this.className) return this.warningMsg('请填写分类名称')
let data = {
name: this.className,
}
if(this.curRow.id){
data.id = this.curRow.id
this.$put(this.api.editClassification,data).then(res => {
this.successMsg('修改成功');
this.classVisible = false
this.getData()
}).catch(res => {});
}else{
this.$post(`${this.api.addClassification}/${this.className}?distinguish=1`).then(res => {
this.successMsg('添加成功');
this.classVisible = false
this.getData()
}).catch(res => {});
}
},
}
};
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,204 @@
<template>
<div class="box">
<breadcrumb :data="'官方资讯管理/栏目内容管理'"></breadcrumb>
<div class="page">
<div class="tabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == activeName}" @click="tabChange(index)">{{item}}</a>
</div>
<div class="btn-wrap">
<el-button class="action-btn" type="primary" size="small" @click="sortSubmit" v-auth="'content:保存排序'">保存排序</el-button>
<el-button class="action-btn" type="primary" size="small" @click="delAllData" v-auth="'content:批量删除'">批量删除</el-button>
<el-button class="action-btn" type="primary" size="small" @click="addArticle" v-auth="'content:新增文章'">新增文章</el-button>
</div>
<div class="page-content">
<el-table ref="table" :data="listData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" width="80" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="title" label="标题">
</el-table-column>
<el-table-column prop="name" label="排序值" width="80" align="center">
<template slot-scope="scope">
<el-input size="small" class="sort-input" width="120" min="1" v-model.number="scope.row.sort" type="number" v-auth="'content:保存排序'"></el-input>
<span>{{scope.row.sort}}</span>
</template>
</el-table-column>
<el-table-column prop="date" label="添加日期" align="center">
<template slot-scope="scope">
{{transferDate(scope.row.date)}}
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="170">
<template slot-scope="scope">
<el-button type="text" @click="editArticle(scope)" v-auth="'content:编辑'">编辑</el-button>
<el-divider direction="vertical"></el-divider>
<el-button type="text" @click="delData(scope.row)" v-auth="'content:删除'">删除</el-button>
</template>
</el-table-column>
<el-table-column prop="name" label="文章发布状态" width="120" align="center">
<template slot-scope="scope">
<el-switch
class="off"
v-model="scope.row.status"
:active-value="0"
:inactive-value="1"
style="margin: 0 5px"
:active-text="scope.row.status ? '关' : '开'"
@change="switchOff($event,scope.row,scope.$index)"
v-auth="'content:禁用'"
></el-switch>
<span>{{scope.row.status ? '禁用' : '启用'}}</span>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="totals" @current-change="handleCurrentChange" :current-page="pageNo">
</el-pagination>
</div>
</div>
</div>
</div>
</template>
<script>
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
activeName: 'first',
tabs: {
first: '栏目内容管理'
},
name: this.$store.state.name,
listData: [],
multipleSelection: [],
pageNo: 1,
pageSize: 10,
totals: 0,
columnId: this.$route.query.id
};
},
components: { breadcrumb },
watch: {
$route(){
this.columnId = this.$route.query.id
this.getData()
}
},
mounted() {
this.getData()
},
methods: {
getData(id){
let data = {
columnId: this.columnId
}
this.$get(`${this.api.queryArticleByCondition}/${this.pageNo}/${this.pageSize}`,data).then(res => {
this.listData = res.data.articleList
this.totals = res.data.total
if(!this.listData.length && this.totals){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
handleSelectionChange(val) {
this.multipleSelection = val
},
handleCurrentChange(val) {
this.pageNo = val
this.getData()
},
addArticle(){
this.$router.push(`/addarticle?columnId=${this.columnId}&sort=${this.listData.length+1}`)
},
editArticle(scope){
this.$router.push(`/addarticle?columnId=${this.columnId}&id=${scope.row.id}&sort=${scope.$index+1}`)
},
delData(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteArticles}?articleIds=${row.id}`).then(res => {
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
transferDate(date){
return date.replace(' 00:00:00','')
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.id
})
let title = newArr[0].title
if(title.length > 14){
title = title.substr(0,14) + '……'
}
this.$confirm(`此批量删除操作不可逆,是否确认删除${title}${newArr.length}个选中项?`, '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteArticles}?articleIds=${delList.join(',')}`).then(res => {
this.$refs.table.clearSelection()
this.successMsg('删除成功');
this.getData()
}).catch(res => {})
})
.catch(() => {});
}else{
this.errorMsg('请先选择数据 !')
}
},
switchOff(val,row,index) {
this.$put(`${this.api.enableArticle}/${row.id}/${val}`)
.then(res => {
val == 1 ? this.warningMsg('该文章已隐藏,对学生端用户不可见') : this.successMsg('该文章已发布,对学生端用户可见')
})
.catch(err => {})
},
sortSubmit(){
if(this.listData.length){
if(this.listData.find(n => n.sort < 1)) return this.errorMsg('排序值最小为1')
let data = {articleList: this.listData}
this.$post(this.api.articleSort, data).then(res => {
this.successMsg('保存成功')
this.getContent(this.columnId)
})
.catch(err => {})
}else{
this.errorMsg('数据为空')
}
}
}
};
</script>
<style lang="scss" scoped>
.btn-wrap{
position: absolute;
top: 15px;
right: 15px;
}
.sort-input{
/deep/.el-input__inner{
padding: 0 0 0 10px;
}
}
.sort-input+span{
display: none;
}
.off+span{
display: none;
}
</style>

@ -0,0 +1,58 @@
<template>
<div>
<breadcrumb :data="'课程资源管理/' + tabs[active]" ref="breadcrumb"></breadcrumb>
<div class="page">
<div class="tabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == active}" @click="tabChange(index)">{{item}}</a>
</div>
<div class="page-content">
<courselist v-if="active == 'first'"></courselist>
<classification v-else></classification>
</div>
</div>
</div>
</template>
<script>
import Setting from '@/setting';
import courselist from './courseList.vue';
import classification from './classification.vue';
import breadcrumb from '@/components/breadcrumb'
export default {
name: 'course',
data() {
return {
active: 'first',
tabs: {
first: '课程管理',
second: '分类管理'
},
showTabs: true
};
},
components: {courselist,classification,breadcrumb},
mounted() {
Setting.dynamicRoute && this.initTabs()
},
methods: {
tabChange(index){
this.active = index
this.$refs.breadcrumb.update('课程资源管理/' + this.tabs[this.active])
},
initTabs(){
let btnPermissions = this.$store.state.btnPermissions
let showStaff = btnPermissions.includes('课程资源管理:课程管理')
let showRole = btnPermissions.includes('课程资源管理:分类管理')
if(!showStaff || !showRole){
this.showTabs = false
}
!showStaff && showRole && (this.active = 'second')
}
}
};
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,705 @@
<template>
<div>
<breadcrumb :data="'课程资源管理/内容设置'" :route="'course'"></breadcrumb>
<div class="page">
<div class="relative">
<div class="p-title">内容设置</div>
<div class="btns">
<template v-if="!sorting">
<el-button type="primary" size="small" round v-throttle @click="addChapter">添加章节</el-button>
<el-button type="primary" size="small" round v-throttle @click="sort">编辑顺序</el-button>
</template>
<template v-else>
<el-button type="primary" size="small" round v-throttle @click="cancelSort">取消</el-button>
<el-button type="primary" size="small" round v-throttle @click="saveSort">保存</el-button>
</template>
</div>
</div>
<div class="page-content">
<div class="m-b-20" v-for="(chapter,index) in chapters" :key="chapter.id">
<div class="flex j-between a-center m-b-10">
<div>{{chapter.name}}</div>
<div>
<template v-if="!sorting">
<el-button class="action-btn" type="primary" size="small" round v-throttle @click="editChapter(chapter)">修改章节名称</el-button>
<el-button class="action-btn" type="primary" size="small" round v-throttle @click="addSection(chapter.id)">添加小节</el-button>
<el-button class="action-btn" type="primary" size="small" round v-throttle @click="delChapter(chapter.id)">删除</el-button>
</template>
<template v-else>
<i class="el-icon-top sort-icon" :class="{disabled: index == 0}" style="margin-right: 5px" @click="sortChapter(chapter,'up',index == 0,index)"></i>
<i class="el-icon-bottom sort-icon" :class="{disabled: index == chapters.length-1}" @click="sortChapter(chapter,'down',index == chapter.length-1,index)"></i>
</template>
</div>
</div>
<el-table :data="chapter.subsectionList" class="table" stripe header-align="center">
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column prop="name" label="资源名称">
</el-table-column>
<el-table-column prop="fileType" label="资源类型" align="center">
<template slot-scope="scope">
{{transferType(scope.row.fileType)}}
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<template v-if="!sorting">
<el-button type="text" @click="preview(scope.row)">查看</el-button>
<el-button type="text" @click="delSection(scope.row)">删除</el-button>
<el-button type="text" @click="editSectionName(scope.row,chapter.id)">修改小节名称</el-button>
<el-button type="text" @click="switchFile(scope.row,chapter.id)">更换文件</el-button>
</template>
<template v-else>
<i class="el-icon-top sort-icon" :class="{disabled: scope.$index == 0}" style="margin-right: 5px" @click="sortSection(index,'up',scope.$index == 0,scope.$index)"></i>
<i class="el-icon-bottom sort-icon" :class="{disabled: scope.$index == chapter.subsectionList.length-1}" @click="sortSection(index,'down',scope.$index == chapter.subsectionList.length-1,scope.$index)"></i>
</template>
</template>
</el-table-column>
</el-table>
</div>
<el-dialog :title="chapterId ? '编辑章节' : '新增章节'" :visible.sync="chapterVisible" width="24%" :close-on-click-modal="false">
<el-form>
<el-form-item>
<el-input placeholder="请输入章节名称,便于对小节归类" v-model="chapterName" maxlength="50"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="chapterVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="chapterSubmit">确定</el-button>
</span>
</el-dialog>
<el-dialog title="添加小节" :visible.sync="sectionVisible" width="24%" @close="closeSection" :close-on-click-modal="false">
<el-form label-width="80px">
<el-form-item label="资源添加">
<el-upload
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:action="this.api.fileupload"
:file-list="uploadList"
name="file"
>
<el-button size="small"><img src="../assets/img/upload.png" alt=""> 上传资源</el-button>
</el-upload>
</el-form-item>
<el-form-item label="小节名称">
<el-input placeholder="请输入小节名称" v-model="sectionName" maxlength="50"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="sectionVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="sectionSubmit">确定</el-button>
</span>
</el-dialog>
<el-dialog title="更换文件" :visible.sync="switchVisible" width="28%" :close-on-click-modal="false" @close="closeSwitch">
<div style="text-align: center">
<el-upload
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-remove="beforeRemove"
:limit="1"
:on-exceed="handleExceed"
:action="this.api.fileupload"
:file-list="uploadList"
name="file"
>
<el-button size="small"><img src="../assets/img/upload.png" alt=""> 上传资源</el-button>
</el-upload>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="switchVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="switchSubmit">确定</el-button>
</span>
</el-dialog>
<el-dialog title="修改小节名称" :visible.sync="sectionNameVisible" width="24%" :close-on-click-modal="false">
<el-form>
<el-form-item>
<el-input placeholder="请输入小节名称" v-model="sectionName" maxlength="50"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="sectionNameVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="sectionNameSubmit">确定</el-button>
</span>
</el-dialog>
<div v-show="previewImg" class="el-image-viewer__wrapper" :class="{active: previewImg}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" @click="previewImg = ''"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="el-image-viewer__canvas">
<img :src="previewImg" class="el-image-viewer__img" style="transform: scale(1) rotate(0deg);margin-top: -1px; max-height: 100%; max-width: 100%;">
</div>
</div>
<div v-show="iframeSrc" class="el-image-viewer__wrapper" :class="{active: iframeSrc}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" :class="{'doc-close': isWord}" :style="{top: isWord ? '50px' : '5px'}" @click="closeIframe"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="el-image-viewer__canvas">
<iframe v-if="iframeSrc" class="fileIframe" id="fileIframe" :src="iframeSrc" frameborder="0"></iframe>
<template v-if="showMask">
<div class="mask" style="width: 200px;height: 30px;top: 53px;right: 320px"></div>
<div class="mask" style="width: 175px;height: 30px;top: 53px;right: 5px"></div>
</template>
<template v-if="showMask1">
<div class="word-mask1" style="width: 200px;height: 50px;"></div>
<div class="word-mask" style="height: 40px;top: 48px;"></div>
<div class="word-mask2" style="top: 55px;left: 28%;width: 44%;height: calc(100% - 80px);"></div>
</template>
<template v-if="showMask2 && iframeSrc">
<div class="excel-mask1" style="height: 48px;"></div>
</template>
</div>
</div>
<div v-show="playAuth" class="el-image-viewer__wrapper" :class="{active: playAuth}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" @click="closePlayer"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="player" id="player"></div>
</div>
<pdf :visible.sync="pdfVisible" :src.sync="pdfSrc"></pdf>
</div>
</div>
</div>
</template>
<script>
import { Loading } from 'element-ui';
import pdf from '@/components/pdf'
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
id: '',
userId: this.$store.state.userLoginId,
chapters: [],
sorting: false,
uploading: false,
uploadList: [],
chapterVisible: false,
chapterId: '',
chapterName: '',
sectionVisible: false,
sectionName: '',
sectionId: '',
switchVisible: false,
sectionNameVisible: false,
fileId: '',
fileName: '',
fileUrl: '',
originalFileName: '',
fileType: '',
playAuth: '',
player: null,
previewImg: '',
iframeSrc: '',
curFile: {},
isAddSection: false,
isWord: false,
isPPT: false,
isExcel: false,
showMask: false,
showMask1: false,
showMask2: false,
loadIns: null,
pdfVisible: false,
pdfSrc: '',
previewing: false
};
},
components: { pdf,breadcrumb },
mounted() {
this.insertScript()
this.id = this.$route.query.id
this.id && this.getData()
if (window.history && window.history.pushState) {
history.pushState(null, null, document.URL);
window.addEventListener("popstate", this.goBack, false);
}
},
destroyed() {
window.removeEventListener("popstate", this.goBack, false);
},
methods: {
getData() {
this.$get(`${this.api.queryChaptersAndSubsections}/${this.id}`)
.then(res => {
this.chapters = res.data.chapterList
})
.catch(err => {
});
},
goBack(){
if(this.previewing){
this.closeIframe()
}else{
history.back()
}
},
iframeOnload(){
document.querySelector('#fileIframe').onload = e => {
if(this.isPPT){
this.showMask = true
}else{
this.showMask = false
}
if(this.isWord){
this.showMask1 = true
}else{
this.showMask1 = false
}
if(this.isExcel){
this.showMask2 = true
}else{
this.showMask2 = false
}
this.loadIns.close()
}
},
insertScript(){
const linkTag = document.createElement('link');
linkTag.rel = 'stylesheet';
linkTag.href = 'https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css';
document.body.appendChild(linkTag);
const scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = 'https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js';
document.body.appendChild(scriptTag);
},
//
beforeUpload(file){
let type = this.transferType(file.name.substring(file.name.lastIndexOf('.') + 1))
if(type != '视频' && type != '图片' && type != 'pdf' && (file.size / 1024 / 1024) > 10){
this.errorMsg('请上传10M以内的文件')
return false
}
this.uploading = true
this.originalFileName = file.name
if(this.isAddSection) this.sectionName = file.name.substring(0,file.name.lastIndexOf("."))
this.fileType = file.name.substring(file.name.lastIndexOf('.')+1)
},
handleExceed(files, fileList) {
this.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
this.uploading = false
this.fileId = res.data.filesResult.fileId
this.fileType = res.data.filesResult.fileType
this.fileUrl = res.data.filesResult.fileUrl
this.fileName = res.data.filesResult.ossFileName
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
if((file.size / 1024 / 1024) < 10){
return this.$confirm(`确定移除 ${file.name}`);
}
},
handleRemove(file, fileList) {
this.uploadList = fileList
},
uploadSure(){
this.importVisible = false
this.pageNo = 1
this.staffGradeId = ''
this.keyword = ''
this.getTeacher()
},
goback() {
this.$router.push('course')
},
transferType(ext){
if('jpg,jpeg,png,gif,svg,psd'.includes(ext)) return '图片'
if('mp4,3gp,mov,m4v,avi,dat,mkv,flv,vob,rmvb,rm,qlv'.includes(ext)) return '视频'
return ext
},
addChapter(){
this.chapterName = ''
this.chapterId = ''
this.chapterVisible = true
},
sort(){
this.sorting = true
},
cancelSort(){
this.sorting = false
},
saveSort(){
this.chapters.forEach((n,k) => {
n.sort = k+1
n.subsectionList.forEach((j,i) => {
j.sort = i+1
})
})
let data = {
chapterVOList: this.chapters
}
this.$post(this.api.reorder,data).then(res => {
this.sorting = false
this.getData()
}).catch(res => {});
},
editChapter(item){
this.chapterId = item.id
this.chapterName = item.name
this.chapterVisible = true
},
delChapter(id){
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteChapter}/${id}`).then(res => {
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
closeSection(){
this.isAddSection = false
},
addSection(id){
this.chapterId = id
this.sectionName = ''
this.fileUrl = ''
this.uploadList = []
this.sectionId = ''
this.isAddSection = true
this.sectionVisible = true
},
chapterSubmit(){
if(!this.chapterName) return this.warningMsg('请填写章节名称')
let data = {
courseId: this.id,
name: this.chapterName
}
if(this.chapterId){
data.id = this.chapterId
this.$put(this.api.editChapter, data).then(res => {
this.successMsg('修改成功');
this.chapterVisible = false
this.getData()
})
.catch(err => {
});
}else{
this.$post(this.api.addChapter, data).then(res => {
this.successMsg('添加成功');
this.chapterVisible = false
this.getData()
})
.catch(err => {
});
}
},
sectionSubmit(){
if(!this.sectionName) return this.warningMsg('请填写小节名称')
if(this.uploading) return this.warningMsg('资源正在上传中,请稍候')
if(!this.fileUrl && !this.fileId) return this.warningMsg('请上传资源')
let data = {
id: this.sectionId,
courseId: this.id,
chapterId: this.chapterId,
name: this.sectionName,
fileId: this.fileId,
fileUrl: this.fileUrl,
fileName: this.fileName,
fileType: this.fileType,
originalFileName: this.originalFileName
}
this.$post(this.api.addSubsection, data).then(res => {
this.successMsg('添加成功');
this.sectionVisible = false
this.getData()
})
.catch(err => {
});
},
closeSwitch(){
this.fileId = ''
this.fileName = ''
this.fileType = ''
this.fileUrl = ''
this.sectionId = ''
},
preview(row){
if(this.transferType(row.fileType) == '视频'){
this.$get(`${this.api.getPlayAuth}/${row.fileId}`).then(res => {
this.playAuth = res.data.playAuth
if(this.player){
this.player.replayByVidAndPlayAuth(row.fileId,this.playAuth)
}else{
this.player = new Aliplayer({
id: 'player',
width: '100%',
autoplay: false,
vid : row.fileId,
playauth : this.playAuth,
encryptType:1, //
})
}
}).catch(res => {})
}else if(this.transferType(row.fileType) == '图片'){
this.previewImg = row.fileUrl
}else if(row.fileType == 'pdf'){
this.pdfSrc = row.fileUrl
this.pdfVisible = true
}else{
this.$get(`${this.api.getSubsection}/${row.id}`).then(res => {
this.previewing = true
this.loadIns = Loading.service()
this.$route.fullPath.includes('#file') || history.pushState({file: true},'文件预览','#' + this.$route.fullPath + '#file')
if(row.fileType == 'pptx'){
this.isPPT = true
this.isWord = false
this.isExcel = false
}else if(row.fileType == 'doc' || row.fileType == 'docx'){
this.isPPT = false
this.isWord = true
this.isExcel = false
}else if(row.fileType == 'xls' || row.fileType == 'xlsx'){
this.isExcel = true
this.isPPT = false
this.isWord = false
}else{
this.isPPT = false
this.isWord = false
this.isExcel = false
}
this.iframeSrc = res.data.previewUrl
this.$nextTick(() => {
this.iframeOnload()
})
})
.catch(err => {
});
}
},
editSectionName(row,chapterId){
this.chapterId = chapterId
this.sectionId = row.id
this.sectionName = row.name
this.sectionNameVisible = true
},
switchFile(row,chapterId,sectionId){
this.uploadList = []
this.curFile = {
fileId: row.fileId,
fileName: row.fileName,
fileType: row.fileType,
fileUrl: row.fileUrl,
}
this.chapterId = chapterId
this.sectionId = row.id
this.sectionName = row.sectionName
this.switchVisible = true
},
switchSubmitFile(){
let data = {
id: this.sectionId,
courseId: this.id,
chapterId: this.chapterId,
name: this.sectionName,
fileId: this.fileId,
fileName: this.fileName,
fileType: this.fileType,
fileUrl: this.fileUrl,
originalFileName: this.originalFileName
}
this.$put(this.api.editSubsection, data).then(res => {
this.successMsg('更换成功');
this.switchVisible = false
this.getData()
})
.catch(err => {
});
},
switchSubmit(){
if(this.uploading) return this.warningMsg('资源正在上传中,请稍候')
if(!this.fileUrl && !this.fileId) return this.warningMsg('请上传资源')
if(this.transferType(this.curFile.fileType) == '视频'){
let data = {
videoIdList: [this.sectionId]
}
this.$del(`${this.api.removeVideo}/${this.curFile.fileId}`).then(res => {
this.switchSubmitFile()
}).catch(res => {});
}else{
this.$del(`${this.api.fileDeletion}?keys=${this.curFile.fileName}`).then(res => {
this.switchSubmitFile()
}).catch(res => {});
}
},
delSection(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteSubsection}/${row.id}`).then(res => {
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
sortChapter(row,type,disabled,index){
if(!disabled){
if(type == 'up'){
let tempItem = this.chapters.splice(index - 1,1)[0]
this.chapters.splice(index,0,tempItem)
}else{
let tempItem = this.chapters.splice(index + 1,1)[0]
this.chapters.splice(index,0,tempItem)
}
}
},
sortSection(chapterIndex,type,disabled,index){
if(!disabled){
let list = this.chapters[chapterIndex].subsectionList
if(type == 'up'){
let tempItem = list.splice(index - 1,1)[0]
list.splice(index,0,tempItem)
}else{
let tempItem = list.splice(index + 1,1)[0]
list.splice(index,0,tempItem)
}
this.chapters[chapterIndex].subsectionList = list
}
},
sectionNameSubmit(){
if(!this.sectionName) return this.warningMsg('请填写小节名称')
let data = {
id: this.sectionId,
courseId: this.id,
chapterId: this.chapterId,
name: this.sectionName
}
this.$put(this.api.editSubsection, data).then(res => {
this.successMsg('修改成功');
this.sectionNameVisible = false
this.getData()
})
.catch(err => {
});
},
closePlayer(){
this.playAuth = ''
this.player.pause()
},
closeIframe(){
this.iframeSrc = ''
this.showMask = false
this.showMask1 = false
this.showMask2 = false
this.previewing = false
},
}
};
</script>
<style scoped lang="scss">
.btns{
position: absolute;
top: 12px;
right: 24px;
.el-button{
font-size: 14px;
}
}
.sort-icon{
font-size: 24px;
cursor: pointer;
&.disabled{
color: #ccc;
cursor: not-allowed
}
}
.el-image-viewer__wrapper{
transform: translateY(-10px);
transition: transform .5s;
&.active{
transform: translateY(0)
}
}
.el-image-viewer__close{
z-index: 10000;
top: 15px;
right: 15px;
&.doc-close{
i{
color: #000 !important;
}
}
}
.player{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 1200px !important;
height: 600px !important;
}
.fileIframe{
z-index: 1;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
}
.mask{
z-index: 1000;
position: fixed;
background-color: rgb(57,58,61);
}
.word-mask{
z-index: 1000;
position: fixed;
right: 0;
width: 100%;
background-color: rgb(243,242,241);
}
.word-mask1{
z-index: 1000;
position: fixed;
top: 0;
right: 0;
background-color: #2b579a;
}
.word-mask2{
z-index: 1000;
position: fixed;
background-color: transparent;
}
.excel-mask1{
z-index: 9;
position: absolute;
top: 0;
left: 20%;
width: 80%;
background-color: #107c41;
}
</style>

@ -0,0 +1,210 @@
<template>
<div>
<div class="tool">
<ul class="filter" style="align-items: flex-start">
<li>
<label>课程分类</label>
<el-select v-model="classificationId" clearable placeholder="请选择课程分类" size="small" @change="getData">
<el-option label="不限" value=""></el-option>
<el-option v-for="(item,index) in classificationList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>搜索</label>
<el-input placeholder="请输入课程名称/创建人" suffix-icon="el-icon-search" v-model="keyword" clearable size="small"></el-input>
</li>
</ul>
<div>
<el-button type="primary" size="small" round @click="addCourse" v-auth="'course:课程管理:新增课程'">新增</el-button>
<el-button type="primary" size="small" round @click="delAllData" v-auth="'course:课程管理:批量删除'">批量删除</el-button>
</div>
</div>
<el-table :data="courseData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" width="80" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="name" label="课程名称">
</el-table-column>
<el-table-column prop="gmtCreate" 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.chapterNum ? scope.row.chapterNum : 0}}({{scope.row.subsectionNum ? scope.row.subsectionNum : 0}}小节)
</template>
</el-table-column>
<el-table-column prop="classification" label="课程分类">
</el-table-column>
<el-table-column label="操作" align="center" width="250">
<template slot-scope="scope">
<el-button type="text" @click="editCourse(scope.row)" v-auth="'course:课程管理:编辑信息'">编辑信息</el-button>
<el-divider direction="vertical" v-auth="'course:课程管理:编辑信息'"></el-divider>
<el-button type="text" @click="config(scope.row)" v-auth="'course:课程管理:配置资源'">内容设置</el-button>
<el-divider direction="vertical" v-auth="'course:课程管理:配置资源'"></el-divider>
<el-button type="text" @click="preview(scope.row)" v-auth="'course:课程管理:预览'">预览</el-button>
<el-divider direction="vertical" v-auth="'course:课程管理:预览'"></el-divider>
<el-button type="text" @click="handleDelete(scope.row)" v-auth="'course:课程管理:删除'">删除</el-button>
</template>
</el-table-column>
<el-table-column label="可授权状态" align="center" width="120">
<template slot-scope="scope">
<el-switch
v-model="scope.row.isEnable"
:active-value="0"
:inactive-value="1"
style="margin: 0 5px"
:active-text="scope.row.isEnable ? '关' : '开'"
@change="switchOff($event,scope.row,scope.$index)"
v-auth="'course:课程管理:禁用'"
></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="totals" @current-change="handleCurrentChange" :current-page="pageNo">
</el-pagination>
</div>
</div>
</template>
<script>
export default {
name: 'dashboard',
data() {
return {
schoolId: this.$store.state.schoolId,
keyword: '',
classificationId: '',
courseData: [],
multipleSelection: [],
classificationList: [],
pageNo: 1,
pageSize: 10,
totals: 0,
};
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted() {
this.getClassification()
this.getData()
},
methods: {
getData() {
let data = {
classificationId: this.classificationId,
name: this.keyword,
}
this.$get(`${this.api.queryCourseByCondition}/${this.pageNo}`,data).then(res => {
this.courseData = res.data.courseList
this.totals = res.data.total
if(!this.courseData.length && this.totals){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
initData(){
this.pageNo = 1
this.getData()
},
getClassification() {
this.$get(this.api.queryAllClassification).then(res => {
this.classificationList = res.data.classificationList
}).catch(res => {});
},
changeType(type) {
this.classificationId = type
this.initData()
},
preview(row){
this.$router.push(`courseSection?id=${row.id}`)
},
config(row){
this.$router.push(`courseConfig?id=${row.id}`)
},
addCourse(){
this.$router.push('addCourse')
},
editCourse(row){
this.$router.push(`addCourse?id=${row.id}`)
},
handleDelete(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteCourse}/${row.id}`).then(res => {
this.successMsg('删除成功');
this.initData()
}).catch(res => {});
})
.catch(() => {});
},
getRowKeys(row) {
return row.customerId;
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.id
})
this.$confirm(`此批量删除操作不可逆,是否确认删除${newArr[0].name}${newArr.length}个选中项?`, '提示', {
type: 'warning'
})
.then(() => {
let data = {
courseIds: delList.join()
}
this.$del(this.api.deleteCourses,data).then(res => {
this.multipleSelection = [];
this.$refs.table.clearSelection()
this.successMsg('删除成功');
this.initData()
}).catch(res => {});
}).catch(() => {});
}else{
this.errorMsg('请先选择数据 !');
}
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
switchOff(val,row,index) {
this.$put(`${this.api.enableGlCourse}?courseId=${row.id}&isEnable=${val}`)
.then(res => {
this.getData()
val == 1 ? this.warningMsg('该教学资源已被禁止授权') : this.successMsg('该教学资源已被调至可对院校授权状态')
})
.catch(err => {});
},
}
};
</script>
<style lang="scss" scoped>
/deep/.tool{
.filter{
.el-input{
min-width: 215px;
}
}
}
</style>

@ -0,0 +1,448 @@
<template>
<div>
<div class="flex p-40">
<div class="cover" :class="{'is-word': showMask1}">
<img v-if="coverUrl" :src="coverUrl" alt="" width="100%" height="100%">
<template v-else-if="iframeSrc">
<iframe class="inner fileIframe" id="fileIframe" :src="iframeSrc" frameborder="0"></iframe>
<template v-if="showMask">
<div class="mask" style="width: 500px;height: 30px;top: 53px;right: 320px"></div>
<div class="mask" style="width: 175px;height: 30px;top: 53px;right: 5px"></div>
</template>
<template v-if="showMask1">
<div class="word-mask" style="height: 40px;"></div>
<div class="word-mask2" style="top: 55px;left: 28%;width: 44%;height: calc(100% - 80px);"></div>
</template>
<template v-if="showMask2">
<div class="excel-mask1" style="height: 48px;"></div>
</template>
</template>
<div class="pdf inner" v-else-if="pdfSrc">
<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="pdfSrc"
:page="currentPage"
@num-pages="pageCount=$event"
@page-loaded="currentPage=$event"
@loaded="loadPdfHandler">
</pdf>
</div>
<div class="inner" v-else-if="playAuth">
<div class="video_wid" id="player"></div>
</div>
</div>
<div class="catalog flex-1">
<div class="list">
<h4 class="title">{{courseName}}</h4>
<div class="desc-wrap">
<div class="desc" :class="{active: desShrink}" v-html="description"></div>
<i class="arrow" :class="{active: desShrink}" v-if="description.length > 40">
<span>...</span>
<img src="../assets/img/arrow-down.png" alt="" @click="desShrink = !desShrink">
</i>
</div>
<div class="chapters">
<template v-if="videoList.length">
<div class="chapter" v-for="(item,index) in videoList" :key="index">
<div class="chapterName">{{item.name}}</div>
<div class="section" v-if="item.subsectionList.length">
<div class="sectionName" v-for="(section,i) in item.subsectionList" :key="i" @click="preview(section)">{{section.name}}</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
import pdf from "vue-pdf";
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import bus from '@/libs/bus'
export default {
data() {
return {
id: this.$route.query.id,
video: 'http://liuwanr.oss-cn-shenzhen.aliyuncs.com/mp4/20200519/1589871025648.mp4',
videoSrc: '',
userId: this.$store.state.userId,
videoList: [],
courseName: '',
description: '',
coverUrl: '',
playAuth: '',
player: null,
previewImg: '',
iframeSrc: '',
isWord: false,
isPPT: false,
isExcel: false,
showMask: false,
showMask1: false,
showMask2: false,
closePosi: {
top: '80px'
},
pdfVisible: false,
pdfSrc: '',
currentPage: 0, // pdf
pageCount: 0, // pdf
fileType: 'pdf', //
desShrink: false
};
},
computed: {
...mapState({
courseId: state => state.courseId,
classId: state => state.classId,
}),
},
components: { pdf },
mounted() {
this.insertScript()
this.getData()
this.getChapter()
},
methods: {
async getData(){
let res = await this.$get(`${this.api.getCourse}/${this.id}`)
this.courseName = res.data.course.name
this.description = res.data.course.description
this.coverUrl = res.data.course.coverUrl
},
async getChapter(){
let res = await this.$get(`${this.api.queryChaptersAndSubsections}/${this.id}`)
this.videoList = res.data.chapterList
},
insertScript(){
const linkTag = document.createElement('link');
linkTag.rel = 'stylesheet';
linkTag.href = 'https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css';
document.body.appendChild(linkTag);
const scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = 'https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js';
document.body.appendChild(scriptTag);
},
transferType(ext){
if('jpg,jpeg,png,gif,svg,psd'.includes(ext)) return '图片'
if('mp4,3gp,mov,m4v,avi,dat,mkv,flv,vob,rmvb,rm,qlv'.includes(ext)) return '视频'
return ext
},
preview(row){
this.player = null
this.playauth = ''
this.coverUrl = ''
this.pdfSrc = ''
this.iframeSrc = ''
if(this.transferType(row.fileType) == '视频'){
this.$get(`${this.api.getPlayAuth}/${row.fileId}`).then(res => {
this.playAuth = res.data.playAuth
this.$nextTick(() => {
if(this.player){
this.player.replayByVidAndPlayAuth(row.fileId,this.playAuth)
}else{
this.player = new Aliplayer({
id: 'player',
width: '100%',
autoplay: false,
vid : row.fileId,
playauth : this.playAuth,
encryptType:1, //
})
}
})
}).catch(res => {})
}else if(this.transferType(row.fileType) == '图片'){
this.coverUrl = row.fileUrl
}else if(row.fileType == 'pdf'){
this.pdfSrc = row.fileUrl
this.pdfVisible = true
}else{
this.$get(`${this.api.getSubsection}/${row.id}`).then(res => {
if(row.fileType == 'pptx'){
this.isPPT = true
this.isWord = false
this.isExcel = false
}else if(row.fileType == 'doc' || row.fileType == 'docx'){
this.isPPT = false
this.isWord = true
this.isExcel = false
}else if(row.fileType == 'xls' || row.fileType == 'xlsx'){
this.isExcel = true
this.isPPT = false
this.isWord = false
}else{
this.isPPT = false
this.isWord = false
this.isExcel = false
}
if(this.isPPT){
this.showMask = true
}else{
this.showMask = false
}
if(this.isWord){
this.showMask1 = true
}else{
this.showMask1 = false
}
if(this.isExcel){
this.showMask2 = true
}else{
this.showMask2 = false
}
this.iframeSrc = res.data.previewUrl
})
.catch(err => {
});
}
},
closePlayer(){
this.playAuth = ''
this.player.pause()
},
closeIframe(){
this.iframeSrc = ''
this.showMask = false
this.showMask1 = false
},
closePdf(){
this.pdfSrc = ''
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
}
}
};
</script>
<style lang="scss" scoped>
$height: 700px;
.video_wid,.cover{
position: relative;
width: 76%;
max-width: 1400px;
height: $height !important;
border: 0;
}
.cover{
img{
border-radius: 8px;
}
&.is-word{
overflow: hidden;
}
}
.fileIframe{
height: $height !important;
}
.video_wid,.inner{
width: 100%;
height: 100% !important;
border: 0;
overflow: auto;
}
.cover.is-word{
.inner{
height: calc(100% + 38px) !important;
margin-top: -38px;
}
}
.video_wid:focus{
outline: none;
}
.catalog{
margin-left: 40px;
}
.list{
height: $height;
overflow-y: auto;
padding: 24px 16px;
background: #fff;
.title{
margin-bottom: 8px;
color: rgba(0, 0, 0, 0.85);
font-size: 20px;
}
.desc-wrap{
position: relative;
.desc{
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 22px;
@include mul-ellipsis(2);
&.active{
display: block;
overflow: visible;
}
}
.arrow{
position: absolute;
bottom: 2px;
right: 0;
display: flex;
justify-content: space-between;
width: 46px;
background-color: #fff;
span{
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
}
img{
width: 16px;
cursor: pointer;
}
&.active{
span{
opacity: 0;
}
img{
transform: rotate(180deg);
}
}
}
}
.chapters{
margin-top: 16px;
max-height: calc(100% - 53px);
overflow: auto;
}
.chapter{
margin-bottom: 20px;
.chapterName{
color: rgba(0, 0, 0, 0.85);
font-size: 16px;
}
.section{
padding: 5px 15px;
margin-top: 8px;
background: rgba(0, 0, 0, 0.02);
.sectionName{
margin: 10px 0;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
cursor: pointer;
@include ellipsis;
}
}
}
}
.el-image-viewer__wrapper{
transform: translateY(-10px);
transition: transform .5s;
&.active{
transform: translateY(0)
}
}
.el-image-viewer__close{
z-index: 2000;
top: 15px;
right: 15px;
&.doc-close{
i{
color: #000 !important;
}
}
}
.list::-webkit-scrollbar {
width: 4px;
}
.list::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0.06);
}
.mask{
z-index: 9;
position: absolute;
background-color: rgb(57,58,61);
}
.word-mask{
z-index: 9;
position: absolute;
top: 0;
right: 0;
width: 100%;
background-color: rgb(243,242,241);
}
.word-mask1{
z-index: 9;
position: absolute;
top: 0;
right: 0;
width: 100%;
background-color: #185abd;
}
.word-mask2{
z-index: 9;
position: absolute;
background-color: transparent;
}
.excel-mask1{
z-index: 9;
position: absolute;
top: 0;
left: 20%;
width: 60%;
background-color: #107c41;
}
/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{
padding: 10px 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
color: #fff;
background-color: #333;
.turn{
margin: 0 10px;
font-size: 18px;
cursor: pointer;
}
}
.pdf-wrap{
width: 80%;
margin: 0 auto;
}
}
</style>

@ -0,0 +1,245 @@
<template>
<div>
<breadcrumb :data="'学校信息列表/客户列表'"></breadcrumb>
<div class="page">
<div class="p-title">客户列表</div>
<div class="page-content">
<div class="tool">
<ul class="filter">
<li>
<label>国家</label>
<el-select v-model="form.countries" placeholder="请选择国家" size="small">
<el-option v-for="(item,index) in countryList" :key="index" :label="item.name" :value="item.name"></el-option>
</el-select>
</li>
<li>
<label>省份</label>
<el-select v-model="form.provinces" clearable placeholder="请选择省份" size="small" @change="getCity()" @clear="clearprovince()">
<el-option v-for="(item,index) in provinceList" :key="index" :label="item.provinceName" :value="item.provinceId"></el-option>
</el-select>
</li>
<li>
<label>城市</label>
<el-select v-model="form.city" clearable placeholder="请选择城市" size="small" :disabled="form.provinces ? false : true" @change="initData()">
<el-option v-for="(item,index) in cityList" :key="index" :label="item.cityName" :value="item.cityId"></el-option>
</el-select>
</li>
<li>
<label>搜索</label>
<el-input style="width: 250px" placeholder="请输入客户名称/管理员姓名/电话" suffix-icon="el-icon-search" v-model="keyword" clearable size="small"></el-input>
</li>
</ul>
<div>
<el-button type="primary" size="small" round @click="addcustomer" v-auth>新增客户</el-button>
<el-button type="primary" size="small" round @click="delAllSelection" v-auth>批量删除</el-button>
</div>
</div>
<el-table :data="customerData" ref="table" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" width="80" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="clientName" label="客户名称">
</el-table-column>
<el-table-column prop="provinceName" label="省份" align="center">
</el-table-column>
<el-table-column prop="cityName" label="城市" align="center">
</el-table-column>
<el-table-column prop="contactPersonName" label="联系人名称" align="center">
</el-table-column>
<el-table-column prop="phone" label="手机号" align="center">
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button type="text" @click="show(scope.row)" v-auth>查看</el-button>
<el-divider direction="vertical" v-auth="'dashboard:查看'"></el-divider>
<el-button type="text" @click="edit(scope.row)" v-auth>编辑</el-button>
<el-divider direction="vertical" v-auth="'dashboard:编辑'"></el-divider>
<el-button type="text" @click="handleDelete(scope.row)" v-auth>删除</el-button>
</template>
</el-table-column>
<el-table-column label="系统使用权限" align="center" width="120">
<template slot-scope="scope">
<el-switch
v-model="scope.row.isDisable"
:active-value="0"
:inactive-value="1"
style="margin: 0 10px 0 5px"
:active-text="scope.row.isDisable ? '关' : '开'"
@change="switchOff($event,scope.row,scope.$index)"
v-auth="'dashboard:禁用'"
></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="totals" @current-change="handleCurrentChange" :current-page="pageNo">
</el-pagination>
</div>
</div>
</div>
</div>
</template>
<script>
import breadcrumb from '@/components/breadcrumb'
export default {
name: 'dashboard',
data() {
return {
countryList: [{
name:'中国'
}],
customerData: [],
keyword: '',
form: {
countries:'中国',
provinces: '',
city: '',
},
multipleSelection: [],
provinceList: [],
cityList: [],
pageNo: 1,
pageSize: 10,
totals: 1,
ruleIds: [],
searchTimer: null
};
},
components: { breadcrumb },
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted() {
this.getData()
this.getProvince()
},
methods: {
getData() {
let data = {
countries: this.form.countries,
provinceId: this.form.provinces,
cityId: this.form.city,
searchContent: this.keyword
}
this.$get(`${this.api.queryClient}/${this.pageNo}/${this.pageSize}`,data).then(res => {
this.customerData = res.data.list
this.totals = res.data.total
if(!this.customerData.length && this.totals){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
initData(){
this.pageNo = 1
this.getData()
},
getProvince(){
this.$get(this.api.queryProvince).then(res => {
this.provinceList = res.data.list
this.$store.commit("provinceData", { provinceList : res.data.list})
}).catch(res => {});
},
//
clearprovince(){
this.form.city = ''
},
getCity(){
this.clearprovince()
this.getCityData()
this.pageNo = 1
this.getData()
},
getCityData(){
if(this.form.provinces != ''){
let data = {
provinceId: this.form.provinces
}
this.$get(this.api.queryCity,data).then(res => {
this.cityList = res.data.list
}).catch(res => {});
}
},
addcustomer(){
this.$router.push('/addcustomer');
},
show(row){
this.$router.push(`/addcustomer?id=${row.id}&show=1`);
},
edit(row){
this.$router.push(`/addcustomer?id=${row.id}`);
},
handleDelete(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteClient}?clientIds=${row.id}`).then(res => {
this.successMsg('删除成功')
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
getRowKeys(row) {
return row.customerId;
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
switchOff(val,row,index) {
let data = {
id: row.id,
isDisable: val
}
this.$post(this.api.updateClient,data).then((res) => {
val == 1 ? this.warningMsg('该院校系统使用权限已关闭') : this.successMsg('该院校系统使用权限已激活')
}).catch((res) => {})
},
delAllSelection() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.id
})
this.$confirm(`此批量删除操作不可逆,是否确认删除${newArr[0].clientName}${newArr.length}个选中项?`, '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteClient}?clientIds=${delList.join()}`).then(res => {
this.$refs.table.clearSelection()
this.multipleSelection = [];
this.successMsg('删除成功')
this.getData()
}).catch(res => {});
}).catch(() => {});
}else{
this.errorMsg('请先选择数据')
}
},
onSearch(){
this.pageNo = 1
this.getData()
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
}
};
</script>
<style lang="scss" scoped>
</style>

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

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

@ -0,0 +1,374 @@
<template>
<div>
<breadcrumb :data="'官方资讯管理/栏目管理'"></breadcrumb>
<div class="page">
<div class="tabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == activeName}" @click="tabChange(index)">{{item}}</a>
</div>
<div class="btn-wrap">
<template v-if="sorting">
<el-button class="action-btn" type="primary" size="small" round @click="cancelSort">取消</el-button>
<el-button class="action-btn" type="primary" size="small" round @click="sortSubmit">保存</el-button>
</template>
<template v-if="!sorting">
<el-button class="action-btn" type="primary" size="small" round @click="openSort" v-auth>更改排序</el-button>
<el-button class="action-btn" type="primary" size="small" round @click="addColumn" v-auth>添加栏目</el-button>
</template>
</div>
<div class="page-content">
<div class="el-table">
<div class="list">
<div class="thead">
<span>栏目名称</span>
<span><em :class="{hide: sorting}" style="font-style: normal">操作</em></span>
</div>
</div>
<el-tree :data="listData" node-key="id" default-expand-all @node-drop="handleDrop" :draggable="sorting" :allow-drop="allowDrop" :allow-drag="allowDrag">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span class="name">{{ node.label }}</span>
<span class="action" v-show="!sorting">
<el-button type="text" @click.stop="editType(data)" v-auth>编辑</el-button>
<el-divider direction="vertical" v-auth="'information:编辑'"></el-divider>
<template v-if="node.level == 1" v-auth="'information:新增'">
<el-button type="text" @click.stop="addType(data)">新增</el-button>
<el-divider direction="vertical"></el-divider>
</template>
<el-button type="text" @click.stop="delData(data)" v-auth>删除</el-button>
</span>
</span>
</el-tree>
</div>
</div>
</div>
<el-dialog :title="isAddColumn ? '添加栏目' : '编辑栏目'" :visible.sync="columnVisible" width="400px" :close-on-click-modal="false" @close="closeColumn">
<el-form>
<el-form-item>
<el-input placeholder="栏目名称" v-model="columnName"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="columnVisible = false"> </el-button>
<el-button size="small" type="primary" @click="columnSubmit"> </el-button>
</span>
</el-dialog>
<el-dialog :title="isAddType ? '添加分类' : '编辑分类'" :visible.sync="typeVisible" width="400px" :close-on-click-modal="false" @close="closeType">
<el-form>
<el-form-item>
<el-input placeholder="分类名称" v-model="typeName"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="typeVisible = false"> </el-button>
<el-button size="small" type="primary" @click="typeSubmit"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import breadcrumb from '@/components/breadcrumb'
export default {
name: 'information',
data() {
return {
activeName: 'first',
tabs: {
first: '栏目管理'
},
name: this.$store.state.name,
originalList: [],
listData: [],
multipleSelection: [],
pageNo: 1,
pageSize: 10,
totals: 0,
columnVisible: false,
columnName: '',
typeVisible: false,
typeName: '',
curRow: {},
sortObj: null,
sorting: false,
curParentId: '',
isAddColumn: false,
isAddType: false,
defaultProps: {
children: 'children',
label: 'label'
}
};
},
components: { breadcrumb },
mounted() {
this.getData()
},
beforeRouteLeave(to, from, next){
if(JSON.stringify(this.originalList) !== JSON.stringify(this.listData)){
this.$confirm('确定返回?排序尚未保存。', '提示', {
type: 'warning'
})
.then(() => {
next()
})
.catch(() => {});
}else{
next()
}
},
methods: {
getData() {
let data = {
page: this.pageNo,
size: this.pageSize
}
this.$get(this.api.queryAllColumns,data).then(res => {
let columnTree = res.data.columnTree
let total = columnTree.length
let list = []
columnTree.forEach((n,k) => {
list.push({
id: n.id,
label: n.name,
level: n.level,
parentId: n.parentId,
sort: n.sort,
children: []
})
n.secondColumn.forEach((j,i) => {
list[k].children.push({
id: j.id,
label: j.name,
level: j.level,
parentId: j.parentId,
sort: j.sort
})
})
total += n.secondColumn.length
})
this.listData = list
this.originalList = JSON.parse(JSON.stringify(this.listData))
this.totals = total
if(!this.listData.length && this.totals){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
delData(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteColumn}/${row.id}`).then(res => {
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
addColumn(){
this.isAddColumn = true
this.columnVisible = true
},
sortSubmit(){
let list = JSON.parse(JSON.stringify(this.listData))
list.forEach((n,k) => {
n.name = n.label
n.parentId = 1
n.level = 1
n.sort = k+1
n.children && n.children.forEach((j,i) => {
j.name = j.label
j.parentId = n.id
j.level = 2
j.sort = i+1
delete j.label
j.secondColumn = []
})
delete n.label
n.secondColumn = n.children
n.children = null
})
let data = {columnTree: list}
this.$post(this.api.reorder,data).then(res => {
this.successMsg('保存成功');
this.sorting = false
this.getData()
}).catch(res => {});
},
columnSubmit(){
if(!this.columnName) return this.warningMsg('请填写栏目名称')
let data = {
level: 1,
parentId: 1,
name: this.columnName
}
if(this.curRow.id){
data.id = this.curRow.id
this.$put(this.api.editColumn,data).then(res => {
this.successMsg('修改成功');
this.columnVisible = false
this.getData()
}).catch(res => {});
}else{
this.$post(this.api.addColumn,data).then(res => {
this.successMsg('添加成功');
this.columnVisible = false
this.getData()
}).catch(res => {});
}
},
addType(row){
this.isAddType = true
this.curRow = row
this.typeVisible = true
},
editType(row){
this.curRow = row
if(row.level == 1){
this.isAddColumn = false
this.columnVisible = true
this.columnName = row.label
}else{
this.isAddType = false
this.typeVisible = true
this.typeName = row.label
}
},
typeSubmit(row){
if(!this.typeName) return this.warningMsg('请填写分类名称')
let data = {
level: 2,
name: this.typeName
}
if(this.curRow.level == 2){
data.id = this.curRow.id
data.parentId = this.curRow.parentId
this.$put(this.api.editColumn,data).then(res => {
this.successMsg('修改成功');
this.typeVisible = false
this.getData()
}).catch(res => {});
}else{
data.parentId = this.curRow.id
this.$post(this.api.addColumn,data).then(res => {
this.successMsg('新增成功');
this.typeVisible = false
this.getData()
}).catch(res => {});
}
},
cancelSort(){
this.sorting = false
this.listData = JSON.parse(JSON.stringify(this.originalList))
this.sortObj.destroy()
},
openSort(){
this.sorting = true
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
onSearch(){
this.pageNo = 1
this.getData()
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
closeColumn(){
this.columnName = ''
this.curRow = {}
},
closeType(){
this.typeName = ''
this.curRow = {}
},
handleDrop(draggingNode, dropNode, dropType, ev) {
// console.log('tree drop: ', dropNode, dropType);
},
allowDrop(draggingNode, dropNode, type) {
if (dropNode.level == 2 && draggingNode.childNodes.length == 0) {
return type !== 'inner'
}else if((draggingNode.childNodes.length > 0 && dropNode.level == 2) || (draggingNode.childNodes.length > 0 && type == 'inner')){
return false
}else {
return true
}
},
allowDrag(draggingNode) {
return draggingNode.data.label.indexOf('三级 3-2-2') === -1;
}
}
};
</script>
<style lang="scss" scoped>
.btn-wrap{
position: absolute;
top: 15px;
right: 15px;
}
.list{
.thead{
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(0, 0, 0, 0.04)!important;
span{
padding: 0.75rem 0.625rem;
text-align: center;
font-size: 14px;
color: rgba(0, 0, 0, 0.85);
font-weight: normal;
box-sizing: border-box;
&:first-child{
padding-left: 23.5vw;
@media(max-width: 1270px){
padding-left: 25.5%;
}
}
&:last-child{
width: 16%;
}
}
}
}
/deep/.el-tree{
.el-tree-node__expand-icon{
margin-left: 22.5vw;
@media(max-width: 1270px){
margin-left: 23.5%;
}
}
.el-tree-node__content{
padding: 20px;
border-bottom: 0.0625rem solid #EBEEF5;
}
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
.name{
line-height: 44px;
}
.action{
width: 8.5vw;
text-align: left;
@media(max-width: 1270px){
width: 16%;
}
}
}
.hide{
opacity: 0;
}
</style>

@ -0,0 +1,205 @@
<template>
<div class="wrap">
<div class="left">
<img class="logo" src="../assets/img/logo-full.png" alt="">
<img class="name" src="../assets/img/system-name.png" alt="">
</div>
<div class="right">
<div v-if="!isReg">
<h2>密码登录</h2>
<el-form :model="loginForm" :rules="loginRules" ref="login" label-width="0px">
<el-form-item prop="username">
<label class="account"></label>
<el-input v-model="loginForm.username" placeholder="请输入账号/手机号" @keyup.enter.native="submitForm()"></el-input>
</el-form-item>
<el-form-item prop="password">
<label class="password"></label>
<el-input type="password" placeholder="请输入密码" v-model="loginForm.password" @keyup.enter.native="submitForm()"></el-input>
</el-form-item>
<el-button class="submit" type="primary" @click="submitForm">登录</el-button>
</el-form>
</div>
</div>
</div>
</template>
<script>
import addRoutes from '@/libs/route/addRoutes';
import Setting from '@/setting';
export default {
data: function() {
return {
loginForm: {
username: '',
// password: 'admin',
password: '',
},
loginRules: {
username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
},
roleDialog: false,
userId: '',
schoolId: '',
schoolName: '',
roleId: '',
roleList: []
};
},
methods: {
updateInfo(data){
this.loginForm.username = data.username
this.loginForm.password = data.password
},
submitForm() {
this.$refs.login.validate(valid => {
if (valid) {
let data = {
account: this.loginForm.username,
password: this.loginForm.password
}
this.$get(this.api.logins,data).then(res => {
if(res.success){
let user = res.data.userInfo
if(user.isPort == 0 || user.isPort == 1){
let routes = res.data.permissions[0].children
sessionStorage.setItem(Setting.usernameKey, this.loginForm.username);
user.userAvatars && this.$store.commit("setAvatarData", { avatar : user.userAvatars});
this.$store.commit("userLoginData", { userId : user.userId,accountRole: user.roleId});
this.$store.commit("userInfo", { name : user.userName,account: user.account,phone: user.phone,schoolId: user.clientId,schoolName: user.clientName});
Setting.dynamicRoute && addRoutes(routes)
sessionStorage.setItem(Setting.storeKey,JSON.stringify(this.$store.state))
this.successMsg('登录成功');
let redirect = decodeURIComponent(this.$route.query.redirect || '/dashboard')
this.$router.replace(redirect)
}else{
this.errorMsg('该用户没有权限')
}
}else{
this.errorMsg(res.message)
}
}).catch(res => {});
}
});
}
},
};
</script>
<style scoped lang="scss">
.wrap {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: url(../assets/img/login_bg.png) 0 0/100% 100% no-repeat;
overflow: hidden;
.left{
margin-right: 200px;
img{
display: block;
}
.logo{
max-width: 242px;
margin-bottom: 60px;
}
.name{
max-width: 663px;
}
}
.right{
padding: 40px 70px 50px;
background-color: #fff;
box-sizing: border-box;
border-radius: 16px;
h2{
font-size: 24px;
color: #000;
text-align: center;
}
.el-form{
margin-top: 30px;
.label{
margin-bottom: 10px;
color: #105CB2;
}
/deep/.el-input__inner{
position: relative;
width: 320px;
height: 46px;
padding: 0 20px 0 40px;
line-height: 46px;
border: 1px solid #E6E6E6;
border-radius: 8px !important;
}
.account,.password{
z-index: 10;
position: absolute;
top: 11px;
left: 12px;
width: 24px;
height: 24px;
background: url(../assets/img/account.png) 0 0/100% 100% no-repeat;
}
.password{
background-image: url(../assets/img/password.png);
}
/deep/.el-form-item__error{
top: 105%;
left: auto;
right: 0;
color: #FFA94E;
}
.submit{
width: 100%;
height: 48px;
margin-top: 30px;
line-height: 48px;
padding: 0;
font-size: 20px;
background-color: #cb221c;
border-radius: 23px;
border: 0;
}
.links{
margin: 20px 0 20px;
}
.ques{
color: #cb221c;
font-size: 14px;
}
.forget{
color: #ffa94e;
font-size: 14px;
}
.login-tips{
margin-bottom: 20px;
font-size: 16px;
color: #105CB2;
text-align: center;
}
.thirdParty{
.item{
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
padding: 10px 0;
color: #AFB5BB;
font-size: 16px;
background-color: #eff0f1;
border-radius: 36px;
cursor: pointer;
img{
width: 40px;
margin-right: 10px;
}
}
}
}
}
}
</style>

@ -0,0 +1,281 @@
<template>
<div>
<breadcrumb :data="'赛事信息管理/竞赛列表'"></breadcrumb>
<div class="page">
<div class="p-title">竞赛列表</div>
<div class="page-content">
<div class="tool" style="align-items: baseline">
<ul class="filter">
<li>
<label>创建时间</label>
<div class="single-choice">
<dl>
<dd>
<span :class="{ active: form.month == item.id }" v-for="(item, index) in dateList" :key="index" @click="changeType(item.id)">{{ item.name }}</span>
</dd>
</dl>
</div>
</li>
<li>
<label>创建区间</label>
<el-date-picker v-model="date" align="right" unlink-panels size="small" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" format="yyyy-MM-dd" value-format="yyyy-MM-dd" clearable></el-date-picker>
</li>
<li>
<label>搜索</label>
<el-input placeholder="请输入竞赛名称/创建人" suffix-icon="el-icon-search" v-model="keyword" clearable size="small"></el-input>
</li>
</ul>
<el-button type="primary" size="small" round @click="add" v-auth>创建竞赛</el-button>
</div>
<el-table ref="table" :data="matchData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="index" width="60" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="name" label="竞赛名称">
</el-table-column>
<el-table-column prop="applicantNum" label="报名人数" width="100" align="center">
<template slot-scope="scope">
{{scope.row.applicantNum ? scope.row.applicantNum : 0}}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80" align="center">
<template slot-scope="scope">
{{transferPublishStatus[scope.row.publishStatus]}}
</template>
</el-table-column>
<el-table-column prop="time" label="竞赛时间" align="center" width="300">
<template slot-scope="scope">
{{scope.row.playStartTime}} ~ {{scope.row.playEndTime}}
</template>
</el-table-column>
<el-table-column prop="gmtCreate" label="创建时间" width="150" align="center">
</el-table-column>
<el-table-column prop="founder" width="100" label="创建人" align="center">
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button type="text" @click="manage(scope.row)" v-auth>管理</el-button>
<el-divider direction="vertical"></el-divider>
<el-button type="text" @click="delData(scope.row)" v-auth>删除</el-button>
</template>
</el-table-column>
<el-table-column label="发布状态" align="center" width="120">
<template slot-scope="scope">
<el-switch
v-model="scope.row.publishStatus"
:active-value="0"
:inactive-value="1"
style="margin: 0 10px 0 5px"
:active-text="scope.row.publishStatus ? '关' : '开'"
@change="switchOff($event,scope.row,scope.$index)"
v-auth="'match:禁用'"
></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="totals" @current-change="handleCurrentChange" :current-page="pageNo">
</el-pagination>
</div>
</div>
</div>
</div>
</template>
<script>
import breadcrumb from '@/components/breadcrumb'
export default {
name: 'match',
data() {
return {
name: this.$store.state.name,
keyword: '',
statusList: [
{
value: '',
name: '不限'
},
{
value: 1,
name: '待发布'
},
{
value: 0,
name: '已发布'
}
],
matchData: [],
form: {
month: '',
publishStatus: '',
startTime: '',
endTime: ''
},
multipleSelection: [],
dateList: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '近一个月'
},
{
id: 3,
name: '近三个月'
},
{
id: 6,
name: '近六个月'
}
],
date: [],
pageNo: 1,
pageSize: 10,
totals: 0,
transferPublishStatus: ['已发布','未发布']
};
},
components: { breadcrumb },
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.endTime = val[1]
}else{
this.form.startTime = ''
this.form.endTime = ''
}
this.initData()
},
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted() {
this.getData()
},
methods: {
getData() {
let data = {}
if(this.form.month) data.month = this.form.month
if(this.keyword) data.name = this.keyword
if(this.form.publishStatus !== '') data.publishStatus = this.form.publishStatus
if(this.form.startTime) data.startTime = this.form.startTime
if(this.form.endTime) data.endTime = this.form.endTime
this.$get(`${this.api.queryContestByCondition}/${this.pageNo}/${this.pageSize }`,data).then(res => {
this.matchData = res.data.contestList
this.totals = res.data.total
this.$refs.table.clearSelection()
if(!this.matchData.length && this.totals){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
initData(){
this.pageNo = 1
this.getData()
},
add(){
this.$router.push('addmatch')
},
manage(row){
this.$router.push(`matchDetail?id=${row.id}`)
},
changeType(type) {
this.form.month = type
},
delData(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteContest}/${row.id}`).then(res => {
this.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.deleteContest,data).then(res => {
this.multipleSelection = [];
this.$refs.table.clearSelection()
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
}else{
this.errorMsg('请先选择数据 !');
}
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
transferTime(date,type){
if(date == '0000-00-00 00:00:00') return '---'
return date
},
switchOff(val,row,index) {
this.$put(`${this.api.publishContest}/${row.id}/${val}`)
.then(res => {
val == 1 ? this.warningMsg('该赛事信息已隐藏对学生端用户不可见') : this.successMsg('该赛事信息已对学生端用户公开')
})
.catch(err => {});
},
}
};
</script>
<style lang="scss" scoped>
/deep/.tool{
.filter{
.el-input{
min-width: 190px;
}
}
}
@media(max-width: 1640px){
.page .page-content .tool .filter{
flex-wrap: wrap;
margin-bottom: -15px;
li{
min-width: 34%;
margin-bottom: 15px;
}
}
}
</style>

@ -0,0 +1,51 @@
<template>
<div>
<breadcrumb :data="'赛事信息管理/大赛详情'" ref="breadcrumb" :route="'match'"></breadcrumb>
<div class="page">
<div class="tabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == active}" @click="tabChange(index)">{{item}}</a>
</div>
<matchintro v-if="active == 'first'"></matchintro>
<matchprogress v-else-if="active == 'second'"></matchprogress>
<matchsignup v-else></matchsignup>
</div>
</div>
</template>
<script>
import matchintro from './matchintro'
import matchprogress from './matchprogress'
import matchsignup from './matchsignup'
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
active: 'first',
tabs: {
first: '大赛详情',
second: '竞赛进展',
third: '报名人员'
},
};
},
components: {
matchintro,
matchprogress,
matchsignup,
breadcrumb
},
created() {
},
methods: {
tabChange(index){
this.active = index
this.$refs.breadcrumb.update('赛事信息管理/' + this.tabs[this.active])
},
}
};
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,400 @@
<template>
<div>
<div class="page-content">
<el-form label-width="170px" label-suffix=":" size="small">
<el-form-item label="竞赛封面(选填)">
<el-upload class="avatar-uploader" accept=".jpg,.png,.jpeg,.gif" :on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" :limit="1" :on-exceed="handleExceed" :action="this.api.fileupload" name="file" >
<img v-if="coverUrl" :src="coverUrl" class="avatar">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip" class="el-upload__tip">
<p>展示宽度为220高度140JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="竞赛封面长图(选填)">
<el-upload class="avatar-uploader avatar-uploader-lg" accept=".jpg,.png,.jpeg,.gif" :on-remove="handleLgRemove" :on-error="uploadError" :on-success="uploadLgSuccess" :before-remove="beforeRemove" :limit="1" :on-exceed="handleExceed" :action="this.api.fileupload" name="file">
<img v-if="carouselUrl" :src="carouselUrl" class="avatar-lg">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip" class="el-upload__tip">
<p>展示宽度为1920高度300JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="竞赛名称">
<div class="d-inline-block">
<el-input placeholder="请输入竞赛名称" v-model="name" clearable></el-input>
</div>
</el-form-item>
<el-form-item label="主办方">
<div class="inline-input">
<div class="input-wrap" v-for="(item,index) in sponsorList" :key="index">
<el-input placeholder="主办方名称" v-model="sponsorList[index]"></el-input>
<i v-if="sponsorList.length > 1" class="remove" @click="delSponsor(index)"></i>
<button v-if="index == 0" class="add-btn" @click="addSponsor">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</div>
</div>
</el-form-item>
<el-form-item label="承办方(选填)">
<div class="inline-input">
<div class="input-wrap" v-for="(item,index) in undertakerList" :key="index">
<el-input placeholder="承办方名称" v-model="undertakerList[index]"></el-input>
<i v-if="undertakerList.length > 1" class="remove" @click="delOrganizer(index)"></i>
<button v-if="index == 0" class="add-btn" @click="addOrganizer">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</div>
</div>
<button v-if="!undertakerList.length" class="add-btn" @click="addOrganizer">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</el-form-item>
<el-form-item label="报名时间">
<el-date-picker v-model="signupTime" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item label="竞赛时间">
<el-date-picker v-model="playTime" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item label="竞赛详情">
<quill :border="true" v-model="description" :height="400" />
</el-form-item>
<el-form-item>
<el-button size="small" v-throttle @click="save(1)">保存</el-button>
<el-button type="primary" v-if="publishStatus == 1" v-throttle @click="save(0)">发布</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import quill from '@/components/quill'
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
id: this.$route.query.id || this.$store.state.matchId,
coverUrl: '',
carouselUrl: '',
publishStatus: 0,
userId: this.$store.state.userLoginId,
uploadList: [],
uploadDataList: [],
name: '',
sponsor: '',
sponsorList: [''],
undertaker: '',
undertakerList: [],
signUpStartTime: '',
signUpEndTime: '',
signupTime: '',
playTime: '',
playStartTime: '',
playEndTime: '',
description: ''
};
},
components: {
quill,
breadcrumb
},
watch: {
signupTime: function(val){
if(val){
this.signUpStartTime = val[0]
this.signUpEndTime = val[1]
}else{
this.signUpStartTime = ''
this.signUpEndTime = ''
}
},
playTime: function(val){
if(val){
this.playStartTime = val[0]
this.playEndTime = val[1]
}else{
this.playStartTime = ''
this.playEndTime = ''
}
}
},
mounted() {
this.getData()
this.commitId()
},
methods: {
save(status) {
this.sponsor = this.sponsorList.filter(d=>d).join()
this.undertaker = this.undertakerList.filter(d=>d).join()
if(!this.name) return this.warningMsg('请填写竞赛名称')
if(status == 0){
if(!this.sponsor) return this.warningMsg('请填写主办方')
if(!this.signUpStartTime) return this.warningMsg('请选择报名时间')
}
let now = new Date().getTime()
let signUpStartTime = new Date(this.signUpStartTime).getTime()
let signUpEndTime = new Date(this.signUpEndTime).getTime()
let playStartTime = new Date(this.playStartTime).getTime()
// if(signUpStartTime && now > signUpStartTime) return this.warningMsg('')
if(!this.playStartTime && status == 0) return this.warningMsg('请选择竞赛时间')
if(playStartTime && playStartTime < signUpEndTime) return this.warningMsg('竞赛时间不能早于报名结束时间')
if(!this.description && status == 0) return this.warningMsg('请填写竞赛详情')
let data = {
id: this.id,
coverUrl: this.coverUrl,
carouselUrl: this.carouselUrl,
description: this.description,
founderId: 1,
name: this.name,
playEndTime: this.playEndTime,
playStartTime: this.playStartTime,
publishStatus: status ? this.publishStatus : 0,
signUpEndTime: this.signUpEndTime,
signUpStartTime: this.signUpStartTime,
sponsor: this.sponsor,
undertaker: this.undertaker
}
if(this.id){
this.$put(this.api.editContest, data).then(res => {
this.successMsg('修改成功');
this.$router.back()
})
.catch(err => {
});
}else{
this.$post(this.api.addContest, data).then(res => {
this.successMsg('创建成功');
this.$router.back()
})
.catch(err => {
});
}
},
getData() {
this.$get(this.api.getContest + '/' + this.id)
.then(res => {
let data = res.data.contest
this.coverUrl = data.coverUrl
this.carouselUrl = data.carouselUrl
this.description = data.description
this.name = data.name
this.playEndTime = data.playEndTime
this.playStartTime = data.playStartTime
this.publishStatus = data.publishStatus
this.signUpEndTime = data.signUpEndTime
this.signUpStartTime = data.signUpStartTime
this.sponsor = data.sponsor
this.undertaker = data.undertaker
this.signupTime = [data.signUpStartTime,data.signUpEndTime]
this.playTime = [data.playStartTime,data.playEndTime]
this.sponsorList = data.sponsor.split(',')
this.undertakerList = data.undertaker.split(',')
})
.catch(err => {
});
},
commitId(){
this.$store.commit("matchData", { matchId : this.id})
},
handleExceed(files, fileList) {
this.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
if(this.coverUrl){
let fileName = this.coverUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {}).catch(res => {});
}
this.coverUrl = res.data.filesResult.fileUrl
},
uploadLgSuccess(res, file, fileList) {
if(this.carouselUrl){
let fileName = this.carouselUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {}).catch(res => {});
}
this.carouselUrl = res.data.filesResult.fileUrl
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
let fileName = this.coverUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {
this.coverUrl = ''
}).catch(res => {});
},
handleLgRemove(file, fileList) {
let fileName = this.carouselUrl.replace('https://liuwanr.oss-cn-shenzhen.aliyuncs.com/','')
this.$del(`${this.api.fileDeletion}?keys=${fileName}`).then(res => {
this.carouselUrl = ''
}).catch(res => {});
},
uploadSure(){
this.BatchUpload = false
this.pageNo = 1
this.keyword = ''
this.getData()
},
goback() {
this.$confirm('确定返回?未更新的信息将不会保存。', '提示', {
type: 'warning'
})
.then(() => {
this.$router.push('/match')
})
.catch(() => {});
},
addSponsor(){
this.sponsorList.push('')
},
delSponsor(index){
this.sponsorList.splice(index,1)
},
addOrganizer(){
this.undertakerList.push('')
},
delOrganizer(index){
this.undertakerList.splice(index,1)
},
},
};
</script>
<style scoped lang="scss">
$upload-width: 220px;
$upload-height: 140px;
$upload-lg-height: 150px;
/deep/.avatar-uploader{
.el-upload {
position: relative;
width: $upload-width;
height: $upload-height;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #cb221c;
}
.uploader-default{
display: flex;
height: $upload-height;
flex-direction: column;
justify-content: center;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i{
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p{
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
}
&.avatar-uploader-lg{
.el-upload {
width: 100%;
max-width: 960px;
height: $upload-lg-height;
.uploader-default{
height: $upload-lg-height;
}
}
}
.avatar {
display: block;
width: $upload-width;
height: $upload-height;
}
.avatar-lg {
display: block;
width: 100%;
height: $upload-lg-height;
}
.el-upload__tip{
margin-top: 0;
p{
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child{
margin-bottom: 5px;
}
}
}
}
/deep/.d-inline-block{
width: 216px;
.el-select,.el-input{
width: 100%;
}
}
.inline-input{
.input-wrap{
display: flex;
align-items: center;
margin-bottom: 10px;
.el-input{
display: inline-block;
width: 216px;
margin-right: 8px;
}
.remove{
width: 16px;
height: 16px;
background: url(../assets/img/close.png) 0 0/cover no-repeat;
cursor: pointer;
}
}
.add-btn{
margin-left: 32px;
}
}
.add-btn{
display: flex;
justify-content: center;
align-items: center;
width: 216px;
line-height: 32px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
background-color: transparent;
border: 1px dashed rgba(0, 0, 0, 0.15);
border-radius: 4px;
cursor: pointer;
i{
margin-right: 8px;
font-size: 14px;
font-weight: bold;
}
}
</style>

@ -0,0 +1,160 @@
<template>
<div class="page-content">
<el-table ref="table" :data="listData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="index" width="60" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="name" label="标题">
<template slot-scope="scope">
<el-input placeholder="请输入标题" v-model="scope.row.title"></el-input>
</template>
</el-table-column>
<el-table-column prop="name" label="详情描述">
<template slot-scope="scope">
<el-input placeholder="请输入详情描述" type="textarea" v-model="scope.row.description"></el-input>
</template>
</el-table-column>
<el-table-column prop="name" label="状态" width="150">
<template slot-scope="scope">
<el-select v-model="scope.row.status" clearable placeholder="请选择状态">
<el-option v-for="(item,index) in statusList" :key="index" :label="item.name" :value="item.value"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="170">
<template slot-scope="scope">
<el-button type="text" @click="saveData(scope.row)">保存</el-button>
<el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="plus" @click="addData">
<i class="el-icon-circle-plus-outline"></i>
</div>
</div>
</template>
<script>
export default {
name: 'matchprogress',
data() {
return {
id: this.$store.state.matchId,
statusList: [
{
value: 0,
name: '未完成'
},
{
value: 1,
name: '进行中'
},
{
value: 2,
name: '已完成'
}
],
listData: [],
multipleSelection: [],
pageNo: 1,
pageSize: 10,
totals: 0
};
},
mounted() {
this.getData()
},
methods: {
getData() {
this.$get(`${this.api.getContestProgress}/${this.id}`).then(res => {
this.listData = res.data.contestProgressList
}).catch(res => {});
},
saveData(row){
let data = row
if(data.title.length){
if(row.id){
this.$put(this.api.editContestProgress,data).then(res => {
this.successMsg('修改成功')
this.getData()
}).catch(res => {});
}else{
this.$post(this.api.addContestProgress,data).then(res => {
this.successMsg('创建成功')
this.getData()
}).catch(res => {});
}
}else{
this.warningMsg('请填写标题')
}
},
entry(){
this.$router.push('/permission')
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
onSearch(){
this.pageNo = 1
this.getData()
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
handleDelete(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.deleteContestProgress}/${row.id}`).then(res => {
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
addData(){
if(this.listData.length){
if(this.listData[this.listData.length-1].id){
this.listData.push({
contestId: this.id,
id: '',
title: '',
description: '',
status: 0
})
}else{
this.warningMsg('请先保存新数据')
}
}else{
this.listData.push({
contestId: this.id,
id: '',
title: '',
description: '',
status: 0
})
}
}
}
};
</script>
<style scoped lang="scss">
.box{
height: calc(100vh - 100px);
overflow: auto;
}
.plus{
padding: 15px 0 0;
text-align: center;
cursor: pointer;
i{
font-size: 24px;
color: #cb221c;
}
}
</style>

@ -0,0 +1,153 @@
<template>
<div class="page-content">
<div class="tool">
<ul class="filter">
<li>
<label>搜索</label>
<el-input placeholder="请输入姓名/手机号" prefix-icon="el-icon-search" v-model="keyword" clearable size="mini"></el-input>
</li>
</ul>
<div>
<el-button type="primary" size="small" round @click="exportAll">全部导出</el-button>
<el-button type="primary" size="small" round @click="exportBatch">批量导出</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.isDisable!=0" width="80" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center">
<template slot-scope="scope">
{{scope.$index + (pageNo - 1) * pageSize + 1}}
</template>
</el-table-column>
<el-table-column prop="school" label="学校">
</el-table-column>
<el-table-column prop="username" label="学生姓名">
</el-table-column>
<el-table-column prop="account" label="账号">
</el-table-column>
<el-table-column prop="phone" label="手机号">
</el-table-column>
<el-table-column label="操作" align="center" width="170">
<template slot-scope="scope">
<el-switch
v-model="scope.row.isDisable"
:active-text="scope.row.isDisable ? '开' : '关'"
:active-value="1"
:inactive-value="0"
style="margin: 0 10px 0 5px"
@change="switchOff($event,scope.row,scope.$index)"
></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="totals" @current-change="handleCurrentChange" :current-page="pageNo">
</el-pagination>
</div>
</div>
</template>
<script>
export default {
name: 'dashboard',
data() {
return {
id: this.$store.state.matchId,
keyword: '',
listData: [],
multipleSelection: [],
pageNo: 1,
pageSize: 10,
totals: 0
};
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.getData()
},500)
}
},
mounted() {
this.getData()
},
methods: {
getData() {
let data = {
contestId: this.id
}
if(this.keyword) data.name = this.keyword
this.$get(`${this.api.queryApplicantByCondition}/${this.pageNo}/${this.pageSize}`,data).then(res => {
this.listData = res.data.applicantList
this.totals = res.data.total
this.$refs.table.clearSelection()
}).catch(res => {});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
onSearch(){
this.pageNo = 1
this.getData()
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
switchOff(val,row,index) {
this.$put(`${this.api.disableApplicant}/${row.id}/${val}`)
.then(res => {})
.catch(err => {});
},
disalbeAllData() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.id
})
this.$confirm('确定要禁用吗?', '提示', {
type: 'warning'
})
.then(() => {
console.log(11,delList.join())
this.$put(`${this.api.disableContests}?ids=${delList.join(',')}`).then(res => {
this.multipleSelection = [];
this.successMsg('禁用成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
}else{
this.errorMsg('请先选择数据 !');
}
},
exportAll(){
location.href = `${this.api.excelExport}/${this.id}`
},
exportBatch(){
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let data = newArr.map(item => {
return item.id
})
// return console.log(11,data)
location.href = `${this.api.batchExport}?ids=${data.join(',')}`
}else{
this.errorMsg('请先选择数据 !');
}
}
}
};
</script>
<style scoped lang="scss">
.box{
height: calc(100vh - 100px);
overflow: auto;
}
</style>

@ -0,0 +1,275 @@
<template>
<div>
<div class="tool">
<ul class="filter"></ul>
<div>
<el-button type="primary" size="small" round @click="addMajor" v-auth="'system:角色权限:新增角色'">新增架构</el-button>
</div>
</div>
<el-table :data="listData" stripe header-align="center" row-key="id" :tree-props="treeProps" :indent="9">
<el-table-column prop="label" label="架构名称">
<template slot-scope="scope">
<span class="text">{{scope.row.label}}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="text" @click="edit(scope.row)">编辑</el-button>
<el-divider direction="vertical"></el-divider>
<template v-if="scope.row.isParent">
<el-button type="text" @click="addDepartment(scope.row)">添加</el-button>
<el-divider direction="vertical"></el-divider>
</template>
<el-button type="text" @click="del(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :title="Form.MajorId ? '编辑名称' : '新增架构'" :visible.sync="isaddMajor" width="24%" @close="closeAdd" :close-on-click-modal="false">
<el-form ref="Form" :model="Form">
<el-form-item prop="majorName">
<el-input :placeholder="Form.MajorId ? '请编辑架构名称' : '请输入架构名称'" v-model="Form.majorName" @change="majorChange"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="isaddMajor = false"> </el-button>
<el-button size="small" type="primary" @click="sure('Form')"> </el-button>
</span>
</el-dialog>
<el-dialog :title="Form.departmentId ? '编辑部门' : '新增部门'" :visible.sync="isAddDepartment" width="24%" @close="closeAdd" :close-on-click-modal="false">
<el-form ref="Form" :model="Form">
<el-form-item prop="departmentName">
<el-input placeholder="请输入部门名称" v-model="Form.departmentName" @change="depChange"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="isAddDepartment = false"> </el-button>
<el-button size="small" type="primary" @click="sureDepartment('Form')"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'role',
data() {
return {
treeProps: {children: 'children', hasChildren: 'hasChildren'},
schoolId: this.$store.state.schoolId,
listData: [],
isaddMajor: false,
isAddDepartment: false,
Form: {
MajorId: '',
majorName: '',
departmentId: '',
departmentName: ''
},
staffstateProfessId: '',
staffstateId: '',
majorNoAdd: true,
depNoAdd: true
};
},
mounted() {
this.getData()
},
methods: {
getData(){
let data = {
schoolId: this.schoolId
}
this.$get(this.api.queryStaffPro,data).then(res => {
let firList = res.data.StaffProfessionalArchitectureList
if(firList){
firList.map(e => {
e.isParent = true
e.id = e.staffProfessionalArchitectureId
e.label = e.staffProfessionalArchitectureName
let data = {
staffProfessionalArchitectureId: e.staffProfessionalArchitectureId
}
this.$get(this.api.queryStaffGrade,data).then(res1 => {
res1.data.staffGradeList.map(e => {
e.id = e.staffGradeId
e.label = e.staffGradeName
})
e.children = res1.data.staffGradeList
}).catch(res => {})
})
setTimeout(() => {
this.listData = firList
},500)
}
}).catch(res => {})
},
addMajor(){
this.Form.MajorId = ''
this.Form.majorName = ''
this.isaddMajor = true
},
edit(item){
if(item.isParent){
this.Form.MajorId = item.staffProfessionalArchitectureId,
this.Form.majorName = item.staffProfessionalArchitectureName
this.isaddMajor = true
}else{
this.Form.departmentId = item.staffGradeId,
this.Form.departmentName = item.staffGradeName
this.isAddDepartment = true
for (let j = 0; j < this.listData.length; j++) {
for (let k = 0; k < this.listData[j].children.length; k++) {
if(this.listData[j].children[k].staffGradeId == item.staffGradeId){
this.Form.MajorId = this.listData[j].staffProfessionalArchitectureId
}
}
}
}
},
async majorChange(){
let res = await this.$get(this.api.queryStaffPAN, { name: this.Form.majorName,schoolId: this.schoolId });
if(res.data.StaffProfessionalArchitecture != null){
this.warningMsg('该一级部门已存在');
this.majorNoAdd = false
}else{
this.majorNoAdd = true
}
},
async depChange(){
let res = await this.$get(this.api.queryStaffName, { staffGradeName: this.Form.departmentName,staffProfessionalArchitectureId: this.Form.MajorId });
if(res.data.staffGrade != null){
this.warningMsg('该二级部门已存在');
this.depNoAdd = false
}else{
this.depNoAdd = true
}
},
sure(){
if(!this.Form.majorName) return this.warningMsg('请输入专业名称')
if(!this.majorNoAdd) return this.warningMsg('该一级部门已存在')
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 => {
this.successMsg('编辑成功')
this.isaddMajor = false
this.getData()
}).catch(res => {})
}else{
this.$post(this.api.addStaffPro,data).then(res => {
this.successMsg('添加成功')
this.isaddMajor = false
this.getData()
}).catch(res => {})
}
},
//
addDepartment(item){
this.Form.departmentId = ''
this.Form.departmentName = ''
this.isAddDepartment = true
this.Form.MajorId = item.staffProfessionalArchitectureId
},
sureDepartment(Form){
if(!this.Form.departmentName) return this.warningMsg('请输入部门名称');
if(!this.depNoAdd) return this.warningMsg('该二级部门已存在');
let data = {
schoolId: this.schoolId,
staffGradeName: this.Form.departmentName,
staffProfessionalArchitectureId: this.Form.MajorId,
staffGradeId: this.Form.departmentId
}
if(this.Form.departmentId){
this.$post(this.api.updateStaffGrade,data).then(res => {
this.successMsg('编辑成功')
this.isAddDepartment = false
this.getData()
}).catch(res => {})
}else{
this.$post(this.api.addStaffGrade,data).then(res => {
this.successMsg('添加成功')
this.isAddDepartment = false
this.getData()
}).catch(res => {})
}
},
closeAdd(){
this.$refs.Form.resetFields()
},
del(item){
if(item.isParent){
this.$confirm('确定要删除该专业吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteStaffPro}?staffProfessionalArchitectureIds=${item.staffProfessionalArchitectureId}`).then(res => {
this.getData()
this.successMsg('删除成功')
}).catch(res => {})
}).catch(() => {})
}else{
this.$confirm('确定要删除该部门吗?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteStaffGrade}?staffGradeIds=${item.staffGradeId}`).then(res => {
this.getData()
this.successMsg('删除成功')
}).catch(res => {})
}).catch(() => {})
}
}
}
};
</script>
<style lang="scss" scoped>
/deep/.el-table{
th:first-child{
.cell{
&:before{
content: '';
display: inline-block;
padding-left: 25vw;
}
}
}
.el-table__body-wrapper{
td:first-child{
.cell{
display: flex;
justify-content: flex-end;
align-items: center;
flex-direction: row-reverse;
i{
font-size: 16px;
}
.text{
&:before{
content: '';
display: inline-block;
padding-left: 25vw;
}
}
.el-table__placeholder + .text{
&:before{
padding-left: 26vw;
}
}
.el-table__expand-icon{
transform: rotate(90deg);
&.el-table__expand-icon--expanded{
transform: rotate(-90deg);
}
}
}
}
}
}
</style>

@ -0,0 +1,434 @@
<template>
<div>
<div class="page">
<div class="tabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == active}" @click="tabChange(index)">{{item}}</a>
</div>
<div class="page-content">
<div v-if="active == 'first'">
<el-form>
<ul class="list">
<li>
<label>头像</label>
<div class="avatar-wrap">
<img :src="this.$store.state.avatar" class="avatar" />
<el-upload :action="this.api.uploadUserAvatars" :data="{userId:this.userId}" name="file" :limit="3" :on-success="getRes">
<el-button size="small"><img src="../assets/img/upload.png" alt=""> 上传头像</el-button>
</el-upload>
</div>
</li>
<li>
<label>姓名</label>
<div>
<el-input v-model="personalInformation.userName" clearable></el-input>
</div>
</li>
<li>
<label>性别</label>
<div>
<el-select v-model="personalInformation.sex">
<el-option v-for="item in sexList" :key="item.value" :label="item.name" :value="item.value"></el-option>
</el-select>
</div>
</li>
<li>
<label>所在国家</label>
<div>
<el-select
v-model="personalInformation.countries"
placeholder
>
<el-option
v-for="item in countryList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</li>
<li>
<label>所在省份</label>
<div>
<el-select
v-model="personalInformation.provinceId"
placeholder
@change="id => getCity(id,1)"
>
<el-option
v-for="item in provinceList"
:key="item.provinceId"
:label="item.provinceName"
:value="item.provinceId"
></el-option>
</el-select>
</div>
</li>
<li>
<label>所在省市</label>
<div>
<el-select
v-model="personalInformation.cityId"
placeholder
:disabled="personalInformation.provinceId ? false : true"
>
<el-option
v-for="item in cityList"
:key="item.cityId"
:label="item.cityName"
:value="item.cityId"
></el-option>
</el-select>
</div>
</li>
<li>
<label>出生年月日</label>
<div>
<el-date-picker
v-model="personalInformation.dateBirth"
:clearable="false"
class="block-right"
type="date">
</el-date-picker>
</div>
</li>
<li>
<label>证件</label>
<div>
<el-input v-model="personalInformation.idnumber" clearable></el-input>
</div>
</li>
<li>
<label>教育程度</label>
<div>
<el-select
v-model="personalInformation.educationDegree"
placeholder="请选择教育程度"
>
<el-option
v-for="(item,index) in educationDegreeList"
:key="index"
:label="item.name"
:value="item.value"
></el-option>
</el-select>
</div>
</li>
</ul>
</el-form>
</div>
<div v-else>
<ul class="list">
<li>
<label>用户账号</label>
<div>
<el-input v-model="personalInformation.account" clearable></el-input>
</div>
</li>
<li>
<label>手机号</label>
<div>
<el-input v-model="personalInformation.phone" clearable></el-input>
</div>
</li>
<li>
<label>邮箱</label>
<div>
<el-input v-model="personalInformation.email" clearable></el-input>
</div>
</li>
<li>
<label>密码</label>
<div>
<el-button size="small" @click="bindPassword">更换密码</el-button>
</div>
</li>
</ul>
</div>
<div style="margin-top: 32px">
<el-button type="primary" size="small" v-throttle @click="save">更新</el-button>
</div>
</div>
</div>
<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 @click="passwordVisible = false"> </el-button>
<el-button type="primary" @click="editPassword"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import _ from 'lodash';
import bus from '@/libs/bus'
export default {
data() {
return {
active: 'first',
tabs: {
first: '用户信息',
second: '账号信息'
},
userId: this.$store.state.userLoginId,
personalInformation: {
name:'',
workNumber:'',
password:"",
phone:'',
email:'',
provinceName:'',
cityName:'',
schoolName:'',
professionalName:'',
},
passwordVisible: false,
passwordForm: {
password: '',
newPassword: '',
reNewPassword: ''
},
sexList: [
{
name: '男',
value: 1
},
{
name: '女',
value: 2
}
],
countryList: [
{
label: '中国'
}
],
form: {},
provinceList: this.$store.state.provinceList, //
cityList: [], //
//
educationDegreeList: [
{
name: '专科',
value: 1
},
{
name: '本科',
value: 2
},
{
name: '硕士',
value: 3
},
{
name: '博士',
value: 4
},
{
name: '其他',
value: 5
}
],
schoolList: [],
curPassword: '',
accountRepeat: false
};
},
mounted() {
this.getdata();
this.getProvince()
this.getSchoolData()
},
methods: {
tabChange(index){
this.active = index
},
getProvince(){
this.$get(this.api.queryProvince).then(res => {
this.provinceList = res.data.list
this.$store.commit("provinceData", { provinceList : this.provinceList});
}).catch(res => {});
},
//
getCity(id,type){
this.personalInformation.cityId = 1
this.getCityData()
},
getCityData(index){
let provinceId = this.personalInformation.provinceId
this.$get(this.api.queryCity,{provinceId}).then(res => {
this.cityList = res.data.list
}).catch(res => {});
},
//
getSchoolData(){
let data = {
searchContent: '',
provinceId: '',
cityId: ''
}
this.$get(`${this.api.queryClient}/1/1000`,data).then(res => {
this.schoolList = res.data.list
}).catch(res => {});
},
accountChange(){
this.$get(`${this.api.getAccount}?account=${this.form.account}`).then(res => {
if(res.data.userInfo){
this.accountRepeat = true
this.warningMsg('该账号已存在')
}else{
this.accountRepeat = false
}
}).catch(res => {});
},
//
getRes(res) {
this.$store.commit('setAvatarData',{avatar:res.message})
bus.$emit('updateAvatar',res.message)
let data = {
userId: this.userId,
userAvatars: res.message
}
this.$post(this.api.userinfoUpdate,data).then(res => {}).catch(res => {})
},
uploadHeadImg: function() {
this.$el.querySelector('.hiddenInput').click();
},
getdata() {
this.$get(`${this.api.userinfo}?userId=${this.userId}`)
.then(res => {
this.personalInformation = res.data.userInfo
this.personalInformation.countries = '中国'
this.curPassword = this.personalInformation.password
this.$nextTick(() => {
if(this.personalInformation.provinceId){
this.getCityData(1)
}
})
})
.catch(err => {
console.log(err);
});
},
bindPassword() {
this.passwordVisible = true
},
editPassword() {
if(!this.passwordForm.password) return this.warningMsg('请输入原密码')
if(!this.passwordForm.newPassword) return this.warningMsg('请输入新密码')
if(!this.passwordForm.reNewPassword) return this.warningMsg('请确认新密码')
if(this.passwordForm.newPassword.length < 6 || this.passwordForm.reNewPassword.length < 6) return this.warningMsg('请输入6位数以上的密码')
if(this.passwordForm.newPassword !== this.passwordForm.reNewPassword) return this.warningMsg('输入的新密码不一致,请重新确认')
if(this.curPassword === this.passwordForm.newPassword) return this.warningMsg('原密码跟新密码不能一致')
let data = {
userId: this.personalInformation.userId,
password: this.passwordForm.password
}
this.$post(this.api.userinfoUpdate,data)
.then(res => {
if(res.success){
this.successMsg('更换成功')
this.curPassword = this.passwordForm.newPassword
this.passwordVisible = false
}else{
this.errorMsg('更换失败')
}
})
.catch(err => {
console.log(err);
});
},
closePassword() {
this.passwordForm = {
password: '',
newPassword: '',
reNewPassword: ''
}
},
save() {
if(this.personalInformation.idnumber && !/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)/.test(this.personalInformation.idnumber)) return this.warningMsg('请输入正确的证件号码')
if(this.accountRepeat) return this.warningMsg('该账号已存在')
if(this.personalInformation.phone && !/^1[3456789]\d{9}$/.test(this.personalInformation.phone)) return this.warningMsg('请输入正确的手机号')
if(this.personalInformation.email && !/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(this.personalInformation.email)) return this.warningMsg('请输入正确的邮箱')
let personalInformation = this.personalInformation
let userInfoEntity = {
idnumber: personalInformation.idnumber,
account: personalInformation.account,
cityId: personalInformation.cityId,
countries: personalInformation.countries,
dateBirth: personalInformation.dateBirth,
educationDegree: personalInformation.educationDegree,
email: personalInformation.email,
phone: personalInformation.phone,
provinceId: personalInformation.provinceId,
clientId: personalInformation.clientId,
clientName: personalInformation.clientName,
sex: personalInformation.sex,
userId: personalInformation.userId,
userName: personalInformation.userName,
}
let data = userInfoEntity
this.$post(this.api.userinfoUpdate,data).then(res => {
if(res.success){
this.successMsg('提交成功')
this.$router.back()
}else{
this.errorMsg('提交失败')
}
}).catch(res => {})
}
}
};
</script>
<style lang="scss" scoped>
/deep/.page{
.page-content{
padding-top: 0;
.list{
li{
display: flex;
align-items: center;
padding: 16px 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
label{
width: 180px;
color: rgba(0, 0, 0, 0.85);
font-size: 16px;
}
.avatar-wrap{
display: inline-flex;
align-items: center;
.avatar{
width: 64px;
height: 64px;
margin-right: 24px;
border-radius: 100%;
}
}
.el-input{
width: 320px;
}
}
}
}
}
</style>

@ -0,0 +1,281 @@
<template>
<div>
<div class="tool">
<ul class="filter">
<li>
<label>搜索</label>
<el-input placeholder="请输入角色名称" prefix-icon="el-icon-search" v-model="keyword" clearable size="small"></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="roleData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange" :row-key="getRowKeys">
<el-table-column type="selection" width="80" 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="roleName" label="角色名称" align="center" width="100">
</el-table-column>
<el-table-column label="角色描述" align="center">
<template slot-scope="scope">
<el-input disabled placeholder="该角色用于管理全部功能权限" v-model="scope.row.remark "></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button type="text" @click="showRole(scope.row)" v-auth="'system:角色权限:查看'">查看</el-button>
<template v-if="scope.row.id != 1">
<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>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="pageNo" layout="total, prev, pager, next" :total="totals">
</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" :model="form" label-width="100px" :disabled="isDetail">
<el-form-item label="角色名称">
<el-input v-model="form.roleName " ref="account" placeholder="请输入角色名称"></el-input>
</el-form-item>
<el-form-item label="角色描述">
<el-input v-model="form.remark " 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>
export default {
name: 'role',
data() {
return {
clientId: this.$store.state.schoolId,
keyword: '',
form: {
roleName : '',
remark : '',
id: ''
},
isDetail: false,
roleData:[],
defaultProps: {
children: 'children',
label: 'name'
},
pageNo: 1,
pageSize: 10,
totals: 0,
multipleSelection: [],
importVisible: false,
isAdd: true,
roleVisible: false,
searchTimer: null,
permissions: [],
checkedIds: []
};
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.getData()
},500)
}
},
mounted() {
this.getData()
},
methods: {
getData() {
let data = {
clientId: this.clientId
}
if(this.keyword.length){
data.name = this.keyword
}
this.$get(`${this.api.queryRoles}/${this.pageNo}/${this.pageSize}`,data).then(res => {
this.roleData = res.data.items
this.totals = res.data.total
if(!this.roleData.length && this.totals){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
closeRole(){
this.isDetail = false
this.form = {
roleName : '',
remark : '',
id: ''
}
this.checkedIds = []
this.permissions = []
},
currentChange(val) {
this.pageNo = val;
this.getData();
},
getPer(){
if(!this.permissions.length){
this.$get(this.api.queryPermissionMenu).then(res => {
this.permissions = res.data.children[0].children
}).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.length){
e.children.every(n => result.includes(n)) || result.splice(result.indexOf(e.id),1)
}
e.children.length && this.handleRolePer(data,e.children)
})
}
return result
},
async getDetail(row){
this.getPer()
let roleRes = await this.$get(`${this.api.getRole}/${row.id}`)
if(roleRes.success){
this.form = roleRes.data.item
let perRes = await this.$get(`${this.api.toAssign}/${row.id}`)
if(perRes.success){
this.checkedIds = this.handleRolePer(perRes.data.rolePermissions,this.permissions)
this.$refs.per.setCheckedNodes(this.checkedIds)
}
}
},
showRole(row){
this.isDetail = true
this.isAdd = false
this.getDetail(row)
this.roleVisible = true
},
editRole(row){
this.isAdd = false
this.getDetail(row)
this.roleVisible = true
},
async saveData() {
if(!this.form.roleName) return this.warningMsg('请填写角色名称')
if(!this.form.remark) return this.warningMsg('请填写角色描述')
// if(!this.$refs.per.getCheckedKeys().length) return this.warningMsg('')
let roleData = {
clientId: this.clientId,
id: this.form.id,
roleName: this.form.roleName,
remark: this.form.remark,
isPort: 1
}
let roleRes = await this.$post(this.api.saveOrUpdate,roleData)
if(roleRes.success){
let permissionId = [...this.$refs.per.getHalfCheckedKeys(),...this.$refs.per.getCheckedKeys()]
let perData = {
clientId: this.clientId,
roleId: roleRes.data.roleId,
permissionId,
isPort: 1
}
let perRes = await this.$post(this.api.doAssign,perData)
if(perRes.success){
this.successMsg('新增成功')
this.getData()
this.roleVisible = false
}
}
},
handleDelete(row) {
this.$confirm('该角色下已有账号,删除角色会将该角色下的账号一并删除,是否继续删除?', '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.removeRole}?roleIds=${row.id}`).then(res => {
if(res.success){
this.successMsg('删除成功');
this.getData()
}
}).catch(res => {})
})
.catch(() => {});
},
getRowKeys(row) {
return row.id;
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delAllSelection() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.id
})
//
this.$confirm(`此批量删除操作不可逆,是否确认删除${newArr[0].roleName}${newArr.length}个选中项?`, '提示', {
type: 'warning'
})
.then(() => {
this.$del(`${this.api.removeRole}?roleIds=${delList.join()}`).then(res => {
if(res.success){
this.$refs.table.clearSelection()
this.successMsg('删除成功');
this.getData()
}
}).catch(res => {})
}).catch(() => {});
}else{
this.errorMsg('请先选择数据 !');
}
}
}
};
</script>
<style lang="scss" scoped>
.no-mb /deep/.el-form-item{
margin-bottom: 0;
}
/deep/.el-row{
padding: 0 !important;
margin-bottom: 0;
}
.per-wrap{
max-height: 300px;
overflow: auto;
}
</style>

@ -0,0 +1,671 @@
<template>
<div>
<div class="tool">
<ul class="filter">
<li>
<label>筛选</label>
<el-cascader :options="orgList" :props="props" collapse-tags clearable size="small" @change="orgChange"></el-cascader>
</li>
<li>
<label>搜索</label>
<el-input style="width: 250px" placeholder="请输入员工姓名/工号/角色名称" v-model="keyword" suffix-icon="el-icon-search" clearable size="small"></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="80" align="center"></el-table-column>
<el-table-column type="index" label="序号" width="55" align="center">
</el-table-column>
<el-table-column prop="userName" label="职工姓名" align="center">
</el-table-column>
<el-table-column prop="account" 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="roleName" label="角色" align="center">
</el-table-column>
<el-table-column prop="lastLoginTime" label="上次登录时间" width="160" align="center">
</el-table-column>
<el-table-column label="操作" width="160" align="center">
<template slot-scope="scope">
<el-button type="text" @click="showTeacher(scope.row)" v-auth="'system:员工管理:查看'">查看</el-button>
<el-divider direction="vertical" v-auth="'system:员工管理:查看'"></el-divider>
<el-button type="text" @click="editTeacher(scope.row)" v-auth="'system:员工管理:编辑'">编辑</el-button>
<el-divider direction="vertical" v-auth="'system:员工管理:编辑'"></el-divider>
<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="pageNo" @current-change="handleCurrentChange" :total="total">
</el-pagination>
</div>
<el-dialog :title="isDetail ? '查看员工' : (isAddManage ? '新增员工' : '编辑员工')" :visible.sync="manageVisible" width="500px" @close="closeTeacher" class="dialog" :close-on-click-modal="false">
<el-form ref="manageForm" :model="manageForm" :rules="rules" label-width="120px" label-suffix=":" :disabled="isDetail">
<el-form-item prop="userAccount" label="账号">
<el-input v-model="manageForm.userAccount" ref="account" placeholder="请输入职工账号" @change="accountChange" maxlength="20"></el-input>
</el-form-item>
<el-form-item prop="userName" label="用户姓名">
<el-input v-model="manageForm.userName" placeholder="请输入员工姓名"></el-input>
</el-form-item>
<el-form-item prop="roleValue" label="账号角色">
<el-select v-model="manageForm.roleValue" placeholder="请选择账号角色">
<el-option v-for="(item,index) in roleList" :key="index" :label="item.roleName" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="uniqueIdentificationAccount" label="唯一标识">
<el-input disabled v-model="manageForm.uniqueIdentificationAccount" placeholder="请输入职工工号获取唯一标识"></el-input>
</el-form-item>
<el-form-item prop="workNumber" label="职工工号">
<el-input v-model="manageForm.workNumber" placeholder="请输入职工工号" @change="workNumberChange"></el-input>
</el-form-item>
<el-form-item prop="major" label="一级部门">
<el-select v-model="manageForm.major" placeholder="请选择一级部门" @change="getDepartment">
<el-option v-for="(item,index) in orgList" :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="manageForm.managerDepartment" placeholder="请选择二级部门" :disabled="manageForm.major ? 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>
<el-form-item prop="phone" label="手机号">
<el-input v-model="manageForm.phone" placeholder="请输入手机号" maxlength="11"></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model="manageForm.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="email" label="默认密码">
<el-input v-model="password" disabled></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer" v-if="!isDetail">
<el-button size="small" @click="manageVisible = false"> </el-button>
<el-button size="small" type="primary" @click="saveSure('manageForm')"> </el-button>
</span>
</el-dialog>
<el-dialog title="查看员工" :visible.sync="staffShowVisible" width="500px" :close-on-click-modal="false">
<ul class="list">
<li>
<span class="name"><i class="required">*</i>账号</span>
<span class="val">{{manageForm.userAccount}}</span>
</li>
<li>
<span class="name"><i class="required">*</i>用户姓名</span>
<span class="val">{{manageForm.userName}}</span>
</li>
<li>
<span class="name">账号角色</span>
<span class="val">{{manageForm.roleValue ? roleList.find(n => n.id == manageForm.roleValue).roleName : ''}}</span>
</li>
<li>
<span class="name">唯一标识</span>
<span class="val">{{manageForm.uniqueIdentificationAccount}}</span>
</li>
<li>
<span class="name"><i class="required">*</i>职工工号</span>
<span class="val">{{manageForm.workNumber}}</span>
</li>
<li>
<span class="name"><i class="required">*</i>一级部门</span>
<span class="val">{{manageForm.major ? orgList.find(n => n.staffProfessionalArchitectureId == manageForm.major).staffProfessionalArchitectureName : ''}}</span>
</li>
<li>
<span class="name"><i class="required">*</i>二级部门</span>
<span class="val">{{manageForm.managerDepartment ? managerDepartmentList.find(n => n.staffGradeId == manageForm.managerDepartment).staffGradeName : ''}}</span>
</li>
<li>
<span class="name">手机号</span>
<span class="val">{{manageForm.phone}}</span>
</li>
<li>
<span class="name">邮箱</span>
<span class="val">{{manageForm.email}}</span>
</li>
<li>
<span class="name">默认密码</span>
<span class="val">{{password}}</span>
</li>
</ul>
</el-dialog>
<el-dialog title="批量导入" :visible.sync="importVisible" width="400px" :close-on-click-modal="false">
<div class="upload-wrap" :class="{lg: uploadFaild}">
<el-button class="download" size="small" @click="downLoad"><img src="../assets/img/download.png" alt=""> 模板下载</el-button>
<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" :data="{schoolId: this.schoolId}" name="file">
<el-button size="small"><img src="../assets/img/upload.png" alt=""> 上传文件</el-button>
</el-upload>
<div class="link" v-if="uploadFaild">
<el-link type="primary" @click="showFaild">导入失败查看原因</el-link>
</div>
</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';
export default {
data() {
return {
pages: 10,
schoolId: this.$store.state.schoolId,
props: { multiple: true },
orgList: [],
isDetail: false,
isAddManage: false,
manageVisible: false,
roleList: [
{
id: '1',
roleName: '超级管理员(系统默认)'
},{
id: '2',
roleName: '普通管理员(系统默认)'
}
],
manageForm: {
clientId: this.$store.state.schoolId,
clientName: this.$store.state.schoolName,
manageId: '',
userName: '',
roleValue: '',
phone: '',
uniqueIdentificationAccount: '',
workNumber: '',
email: '',
major: '',
managerDepartment: '',
userAccount: '',
major: '',
schoolId: this.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' }
],
uniqueIdentificationAccount: [
// { required: true, message: '', trigger: 'blur' },
],
major: [
{ required: true, message: '请选择一级部门', trigger: 'change' }
],
workNumber: [
{ required: true, message: '请输入职工工号', trigger: 'blur' },
{
pattern: /^[A-Za-z0-9]+$/,
message: '请输入正确的职工工号',
trigger: 'blur'
}
],
managerDepartment: [
{ 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' }
// ],
},
staffShowVisible: false,
listData: [],
importVisible: false,
keyword: '',
pageNo: 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: '',
NumberNoAdd: '',
platformId: this.$store.state.platformId,
schoolList: [],
uploadFaild: false,
token: '',
accountRepeat: false,
workNumberRepeat: false,
originalAccount: '',
originalWorkNumber: '',
password: Setting.initialPassword,
submiting: false
};
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted(){
this.getOrg()
this.getData()
this.getRoles()
},
methods: {
getOrg(){
let data = {
schoolId: this.schoolId
}
this.$get(this.api.queryStaffPro,data).then(res => {
let firList = res.data.StaffProfessionalArchitectureList
if(firList){
firList.map(e => {
e.isParent = true
e.value = e.staffProfessionalArchitectureId
e.label = e.staffProfessionalArchitectureName
let data = {
staffProfessionalArchitectureId: e.staffProfessionalArchitectureId
}
this.$get(this.api.queryStaffGrade,data).then(res1 => {
res1.data.staffGradeList.map(e => {
e.value = e.staffGradeId
e.label = e.staffGradeName
})
e.children = res1.data.staffGradeList
}).catch(res => {})
})
setTimeout(() => {
this.orgList = firList
},500)
}
}).catch(res => {})
},
getData(){
let data = {
staffProfessionalArchitectureIds: this.oneDepartmentIds,
staffGradeIds: this.twoDepartmentIds,
searchContent: this.keyword,
schoolId: this.schoolId
}
this.$get(`${this.api.queryStaff}/${this.pageNo}/${this.pageSize}`,data).then(res => {
this.listData = res.data.staffList
this.total = res.data.total
if(!this.listData.length && this.total){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
initData(){
this.pageNo = 1
this.getData()
},
orgChange(node){
this.twoDepartmentIds = node.map(n => n[1]).toString()
this.getData()
},
getRoles() {
this.$get(this.api.getRoles,{clientId: this.schoolId}).then(res => {
this.roleId = res.data.data[0].id
this.roleList = this.roleList.concat(res.data.data)
})
},
getSchoolData(){
let data = {
schoolName: ''
}
this.$get(this.api.querySchool,data).then(res => {
this.schoolList = res.message
}).catch(res => {});
},
closeTeacher(){
this.$refs.manageForm.resetFields()
this.manageForm.managerDepartment = ''
this.manageForm.major = ''
this.manageForm.workNumber = ''
this.manageForm.teacherDepartment = ''
this.manageForm.teacherMajor = ''
this.manageForm.teacherWorkNumber = ''
this.manageForm.userId = ''
this.manageForm.staffId = ''
},
addTeacher(){
this.isDetail = false
this.manageVisible = true
this.isAddManage = true
this.manageForm.manageId = ''
},
getStaffDetail(userId){
this.$get(`${this.api.getStaff}/${userId}`).then(res => {
let user = res.data.userInfo;
let or = res.data.staff;
this.manageForm.uniqueIdentificationAccount = user.uniqueIdentificationAccount
this.manageForm.clientId = user.clientId
this.manageForm.clientName = user.clientName
this.manageForm.userName = user.userName
this.manageForm.phone = user.phone
this.manageForm.email = user.email
this.manageForm.userAccount = user.account
this.originalAccount = Number(user.account)
this.manageForm.userId = user.userId
this.manageForm.schoolId = user.schoolId
this.manageForm.roleValue = or.roleId
this.manageForm.major = or.staffProfessionalArchitectureId
this.manageForm.managerDepartment = or.staffGradeId
this.manageForm.workNumber = or.workNumber
this.originalWorkNumber = or.workNumber
this.manageForm.staffId = or.staffId
this.getDepartment(1)
}).catch(res => {});
},
editTeacher(row){
this.isDetail = false
this.manageVisible = true
this.isAddManage = false
this.AccountNoAdd = false
this.manageForm.manageId = row.staffId
this.getStaffDetail(row.staffId)
},
showTeacher(row){
this.staffShowVisible = true
this.isDetail = true
this.isAddManage = false
this.AccountNoAdd = false
this.manageForm.manageId = row.staffId
this.getStaffDetail(row.staffId)
},
getDepartment(isDetail){
if(!isDetail) this.manageForm.managerDepartment = ''
let data = {
staffProfessionalArchitectureId: this.manageForm.major
}
this.$get(this.api.queryStaffGrade,data).then(res => {
this.managerDepartmentList = res.data.staffGradeList
}).catch(res => {});
},
accountChange(){
if(this.manageForm.userAccount !== this.originalAccount){
this.$get(`${this.api.getAccount}?account=${this.manageForm.userAccount}`).then(res => {
if(res.data.userInfo){
this.accountRepeat = true
this.warningMsg('该账号已存在')
}else{
this.accountRepeat = false
}
}).catch(res => {});
}else{
this.accountRepeat = false
}
},
workNumberChange(){
if(this.manageForm.workNumber !== this.originalWorkNumber){
this.$get(`${this.api.getWorkNumber}?workNumber=${this.manageForm.workNumber}`).then(res => {
if(res.data.staff){
this.workNumberRepeat = true
this.warningMsg('该工号已存在')
}else{
this.workNumberRepeat = false
}
}).catch(res => {});
}else{
this.workNumberRepeat = false
}
},
async saveSure(manageForm){
if(this.submiting) return false
this.$refs[manageForm].validate((valid) => {
if (valid) {
if(this.accountRepeat) return this.warningMsg('该账号已存在')
if(this.workNumberRepeat) return this.warningMsg('该工号已存在')
let data = {
userInfo: {
userId: this.manageForm.userId,
userName: this.manageForm.userName,
account: this.manageForm.userAccount,
schoolId: this.schoolId,
clientId: this.manageForm.clientId,
clientName: this.manageForm.clientName,
roleId: this.manageForm.roleValue,
phone: this.manageForm.phone,
email: this.manageForm.email,
isPort: 1,
uniqueIdentificationAccount: this.manageForm.uniqueIdentificationAccount ? this.manageForm.uniqueIdentificationAccount : Date.parse(new Date()),
}
}
let oneDepartmentName = '';
for(let i in this.orgList){
if(this.orgList[i].staffProfessionalArchitectureId == this.manageForm.major) {
oneDepartmentName = this.orgList[i].staffProfessionalArchitectureName
break;
}
}
let twoDepartmentName = this.managerDepartmentList.find((n) => {
return n.staffGradeId == this.manageForm.managerDepartment
}).staffGradeName;
data.staff = {
roleId: this.manageForm.roleValue,
isPort: 1,
schoolId: this.schoolId,
clientId: this.manageForm.clientId,
clientName: this.manageForm.clientName,
staffId: this.manageForm.staffId,
userId: this.manageForm.userId,
workNumber: this.manageForm.workNumber,
staffProfessionalArchitectureId: this.manageForm.major,
staffGradeId: this.manageForm.managerDepartment,
staffProfessionalArchitectureName: oneDepartmentName,
staffGradeName: twoDepartmentName,
};
this.submiting = true
if(this.manageForm.manageId){
this.$post(this.api.updateStaff,data).then(res => {
this.submiting = false
this.manageVisible = false
this.successMsg('编辑成功');
this.getData()
}).catch(res => {
this.submiting = false
});
}else{
this.$post(this.api.addStaff,data).then(res => {
this.submiting = false
this.manageVisible = false
this.successMsg('添加成功');
this.getData()
}).catch(res => {
this.submiting = false
});
}
}else{
return false;
}
})
},
delTeacher(row){
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
let data = {
staffIds: row.staffId
}
this.$del(this.api.deleteStaffs,data).then(res => {
this.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.staffId
})
//
this.$confirm(`此批量删除操作不可逆,是否确认删除${newArr[0].userName}${newArr.length}个选中项?`, '提示', {
type: 'warning'
})
.then(() => {
let data = {
staffIds: delList.join(',')
}
this.$del(this.api.deleteStaffs,data).then(res => {
this.$refs.table.clearSelection()
this.successMsg('删除成功')
this.getData()
}).catch(res => {});
}).catch(() => {});
}else{
this.errorMsg('请先选择数据 !')
}
},
batchImport(){
this.importVisible = true
this.uploadList = []
this.uploadFaild = false
},
searchTeacher(){
this.pageNo = 1;
this.getData()
},
handleCurrentChange(val) {
this.pageNo = val;
this.getData();
},
downLoad(){
location.href = this.api.downloadStaffTemp
},
showFaild(){
location.href = `${this.api.exportFailureStaff}?token=${this.token}`
},
//
handleExceed(files, fileList) {
this.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
uploadSuccess(res, file, fileList) {
this.uploadFaild = false
if(res.success){
if(res.data.data.token){
this.token = res.data.data.token
this.uploadFaild = true
}else{
this.successMsg('上传成功')
}
}else{
res.data.message ? this.errorMsg(res.data.message) : this.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.pageNo = 1
this.keyword = ''
this.getData()
}
}
};
</script>
<style lang="scss" scoped>
/deep/.dialog{
.el-form-item{
.el-form-item__label{
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
&:before{
margin-right: 0;
color: #CC221C;
}
}
}
.el-input,.el-select{
width: 100%;
}
}
.list{
li{
display: flex;
justify-content: center;
align-items: center;
margin: 32px 0;
.name,.val{
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
}
.name{
width: 45%;
text-align: right;
}
.val{
width: 55%;
}
}
}
</style>

@ -0,0 +1,68 @@
<template>
<div>
<breadcrumb :data="'平台分管设置/' + tabs[active]" ref="breadcrumb"></breadcrumb>
<div class="page">
<div class="tabs" v-if="showTabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == active}" @click="tabChange(index)">{{item}}</a>
</div>
<div class="page-content">
<staff v-if="active == 'staff'" v-auth="'平台分管设置:员工管理'"></staff>
<role v-else-if="active == 'role'" v-auth="'平台分管设置:角色权限'"></role>
<organization v-else v-auth="'平台分管设置:角色权限'"></organization>
</div>
</div>
</div>
</template>
<script>
import Setting from '@/setting'
import staff from './staff.vue'
import role from './role.vue'
import organization from './organization.vue'
import breadcrumb from '@/components/breadcrumb'
export default {
data() {
return {
active: 'staff',
userId: this.$store.state.userId,
tabs: {
staff: '员工管理',
role: '角色权限',
organization: '架构管理'
},
showTabs: true
};
},
components: {
staff,
role,
organization,
breadcrumb
},
created() {
Setting.dynamicRoute && this.initTabs()
},
methods: {
tabChange(index){
this.active = index
this.$refs.breadcrumb.update('平台分管设置/' + this.tabs[this.active])
},
initTabs(){
let btnPermissions = this.$store.state.btnPermissions
let showStaff = btnPermissions.includes('平台分管设置:员工管理')
let showRole = btnPermissions.includes('平台分管设置:角色权限')
if(!showStaff || !showRole){
this.showTabs = false
}
!showStaff && showRole && (this.active = 'role')
}
}
};
</script>
<style lang="scss" scoped>
.tabs{
margin-bottom: 0;
}
</style>

@ -0,0 +1,474 @@
<template>
<div>
<breadcrumb :data="'学校用户管理/用户列表'"></breadcrumb>
<div class="page">
<div class="p-title">用户列表</div>
<div class="page-content">
<div class="tool">
<ul class="filter">
<li>
<label>搜索</label>
<el-input placeholder="请输入所属学校/用户姓名" suffix-icon="el-icon-search" v-model="keyword" clearable size="small"></el-input>
</li>
</ul>
<div>
<el-button type="primary" size="small" round @click="adduser" v-auth>新增用户</el-button>
<el-button type="primary" size="small" round @click="batchImport" v-auth>批量导入</el-button>
<el-button type="primary" size="small" round @click="delAllSelection" v-auth>批量删除</el-button>
</div>
</div>
<el-table :data="userData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" width="80" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="80" label="序号" align="center">
</el-table-column>
<el-table-column prop="clientName" label="所属学校">
</el-table-column>
<el-table-column prop="name" label="姓名" align="center">
</el-table-column>
<el-table-column prop="account" label="账号" align="center">
</el-table-column>
<el-table-column prop="role" label="账号角色" align="center">
<template slot-scope="scope">
{{roleStatus(scope.row.roleId)}}
</template>
</el-table-column>
<el-table-column prop="loginNumber" label="登录次数" align="center">
</el-table-column>
<el-table-column prop="lastLoginTime" label="上次登录时间" align="center">
<template slot-scope="scope">
{{scope.row.lastLoginTime == '0000-00-00 00:00:00' ? '' : scope.row.lastLoginTime}}
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="240">
<template slot-scope="scope">
<el-button type="text" @click="show(scope.row)" v-auth>查看</el-button>
<el-divider direction="vertical" v-auth="'user:查看'"></el-divider>
<el-button type="text" @click="edit(scope.row)" v-auth>编辑</el-button>
<el-divider direction="vertical" v-auth="'user:编辑'"></el-divider>
<el-button type="text" @click="resetPassword(scope.row)" v-auth>重置密码</el-button>
<el-divider direction="vertical" v-auth="'user:重置密码'"></el-divider>
<el-button type="text" @click="handleDelete(scope.row)" v-auth>删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="pageNo" layout="total, prev, pager, next" :total="totals">
</el-pagination>
</div>
</div>
</div>
<el-dialog :title="isAdd ? '新增用户' : '编辑用户'" :visible.sync="userVisible"
width="500px" @close="closeTeacher" class="dialog" :close-on-click-modal="false">
<el-form ref="form" :model="form" :rules="rules" label-width="100px" :disabled="isDetail">
<el-form-item prop="account" label="账号">
<el-input v-model="form.account" ref="account" placeholder="请输入账号" @change="accountChange" maxlength="20"></el-input>
</el-form-item>
<el-form-item prop="name" label="用户姓名">
<el-input v-model="form.name" placeholder="请输入用户姓名"></el-input>
</el-form-item>
<el-form-item prop="roleValue" label="账号角色">
<el-checkbox-group v-model="form.roleValue" :disabled="true">
<el-checkbox label="超级管理员"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item prop="clientId" label="所属学校">
<el-select v-model="form.clientId" clearable placeholder="请选择所属学校" filterable style="width: 100%;">
<el-option v-for="(item,index) in clientList" :key="index" :label="item.clientName" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer" v-if="!isDetail">
<el-button size="small" @click="userVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="saveData">确定</el-button>
</span>
</el-dialog>
<el-dialog title="查看用户" :visible.sync="userShowVisible" width="500px" class="dialog" :close-on-click-modal="false">
<ul class="list">
<li>
<span class="name"><i class="required">*</i>账号</span>
<span class="val">{{form.account}}</span>
</li>
<li>
<span class="name"><i class="required">*</i>用户姓名</span>
<span class="val">{{form.name}}</span>
</li>
<li>
<span class="name">账号角色</span>
<span class="val">超级管理员</span>
</li>
<li>
<span class="name"><i class="required">*</i>所属学校</span>
<span class="val">{{form.clientId ? clientList.find(n => n.id == form.clientId).clientName : ''}}</span>
</li>
</ul>
</el-dialog>
<el-dialog title="批量导入" :visible.sync="importVisible" width="400px" :close-on-click-modal="false">
<div class="upload-wrap" :class="{lg: uploadFaild}">
<el-button class="download" size="small" @click="downLoad"><img src="../assets/img/download.png" alt=""> 模板下载</el-button>
<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.uploadFileUser" :file-list="uploadList" name="file">
<el-button size="small"><img src="../assets/img/upload.png" alt=""> 上传文件</el-button>
</el-upload>
<div class="link" v-if="uploadFaild">
<el-link type="primary" @click="showFaild">导入失败查看原因</el-link>
</div>
</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 breadcrumb from '@/components/breadcrumb'
export default {
name: 'user',
data() {
return {
clientId: this.$store.state.schoolId,
form: {
id: '',
name: '',
account: '',
roleValue: ['超级管理员'],
clientId: '',
clientName: ''
},
rules: {
account: [
{ required: true, message: '请输入账号', trigger: 'blur' },
{
pattern: /^[A-Za-z0-9]+$/,
message: '请输入正确的账号',
trigger: 'blur'
}
],
name: [
{ required: true, message: '请输入用户姓名', trigger: 'blur' }
],
clientId: [
{ required: true, message: '请选择所属学校', trigger: 'change' },
]
},
userData:[],
keyword: '',
pageNo: 1,
pageSize: 10,
totals: 0,
multipleSelection: [],
clientList: [],
isAdd: true,
isDetail: false,
userVisible: false,
userShowVisible: false,
searchTimer: null,
curRow: {},
accountRepeat: false,
uploadList: [],
importVisible: false,
uploadFaild: false,
token: '',
originalAccount: '',
submiting: false
};
},
components: { breadcrumb },
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted() {
this.getData()
this.getClient()
},
methods: {
getData() {
let data = {
searchContent: this.keyword,
current: this.pageNo,
pageSize: this.pageSize
}
this.$get(`${this.api.queryUser}/${this.pageNo}/${this.pageSize}`,data).then(res => {
this.userData = res.data.list
this.totals = res.data.total
if(!this.userData.length && this.totals){
this.pageNo--
this.getData()
}
}).catch(res => {});
},
initData(){
this.pageNo = 1
this.getData()
},
accountChange(){
if(this.form.account !== this.originalAccount){
this.$get(`${this.api.getAccount}?account=${this.form.account}`).then(res => {
if(res.data.userInfo){
this.accountRepeat = true
this.warningMsg('该账号已存在')
}else{
this.accountRepeat = false
}
}).catch(res => {});
}else{
this.accountRepeat = false
}
},
getClient(){
let data = {
searchContent: '',
provinceId: '',
cityId: ''
}
this.$get(`${this.api.queryClient}/1/1000`,data).then(res => {
this.clientList = res.data.list
}).catch(res => {});
},
closeTeacher(){
this.$refs.form.clearValidate()
this.form = {
id: '',
name: '',
account: '',
roleValue: ['超级管理员'],
clientId: '',
clientName: ''
}
this.curRow = {}
},
currentChange(val) {
this.pageNo = val;
this.getData();
},
adduser(){
this.isDetail = false
this.isAdd = true
this.userVisible = true
},
fillForm(row){
this.form.id = row.id
this.form.userId = row.userId
this.form.account = row.account
this.originalAccount = Number(row.account)
this.form.name = row.name
this.form.clientId = row.clientId
this.form.clientName = row.clientName
},
show(row){
this.fillForm(row)
this.userShowVisible = true
},
edit(row){
this.isDetail = false
this.isAdd = false
this.fillForm(row)
this.userVisible = true
},
saveData() {
if(this.submiting) return false
this.$refs.form.validate((valid) => {
if (valid) {
if(this.accountRepeat) return this.warningMsg('该账号已存在')
this.form.clientName = this.clientList.find(n => n.id == this.form.clientId).clientName
let form = this.form
let data = {
userInfo: {
id: form.id,
isPort: 2,
userId: form.userId,
account: form.account,
clientId: form.clientId,
clientName: form.clientName,
creationTime: this.formatDate(new Date().getTime()),
roleId: 1,
uniqueIdentificationAccount: new Date().getTime(),
userName: form.name,
},
userManagement: {
id: form.id,
isPort: 2,
userId: form.userId,
account: form.account,
clientId: form.clientId,
clientName: form.clientName,
name: form.name,
roleId: 1,
}
}
this.submiting = true
if(this.form.id) {
this.$post(this.api.updateUser,data).then(res => {
this.submiting = false
if(res.success) {
this.successMsg('修改成功');
this.userVisible = false
this.getData()
}else{
this.errorMsg(res.message);
}
}).catch(res => {
this.submiting = false
});
}else{
this.$post(this.api.addUser,data).then(res => {
this.submiting = false
if(res.success) {
this.successMsg('新增成功');
this.userVisible = false
this.getData()
}else{
this.errorMsg(res.message);
}
}).catch(res => {
this.submiting = false
});
}
}else{
return false;
}
})
},
handleDelete(row) {
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteUser}?userIds=${row.id}`).then(res => {
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
resetPassword(row){
this.$confirm(`重置后的密码为:${Setting.initialPassword},确定重置?`, '提示', {
}).then(() => {
let data = {
userId: row.userId,
password: Setting.initialPassword
}
this.$post(this.api.userinfoUpdate,data).then(res => {
if(res.success){
this.successMsg('重置成功')
}else{
this.errorMsg('重置失败')
}
}).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.id
})
//
this.$confirm(`此批量删除操作不可逆,是否确认删除${newArr[0].name}${newArr.length}个选中项?`, '提示', {
type: 'warning'
})
.then(() => {
this.$post(`${this.api.deleteUser}?userIds=${delList.join(',')}`).then(res => {
this.$refs.table.clearSelection()
this.multipleSelection = [];
this.successMsg('删除成功');
this.getData()
}).catch(res => {});
}).catch(() => {});
}else{
this.errorMsg('请先选择数据 !');
}
},
batchImport(){
this.importVisible = true
this.uploadList = []
this.uploadFaild = false
},
handleExceed(files, fileList) {
this.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
);
},
downLoad(){
location.href = this.api.downloadUserTemp
},
showFaild(){
location.href = `${this.api.exportFailureUser}?token=${this.token}`
},
uploadSuccess(res, file, fileList) {
this.uploadFaild = false
if(res.success){
if(res.data.data.token){
this.token = res.data.data.token
this.uploadFaild = true
}else{
this.successMsg('上传成功')
}
}else{
res.data.message ? this.errorMsg(res.data.message) : this.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.pageNo = 1
this.keyword = ''
this.getData()
},
}
};
</script>
<style lang="scss" scoped>
.list{
li{
display: flex;
justify-content: center;
align-items: center;
margin: 32px 0;
.name,.val{
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
}
.name{
width: 45%;
text-align: right;
}
.val{
width: 55%;
}
}
}
</style>

@ -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.name}:${el.innerText}`
}
const btnPermissions = store.state.btnPermissions;
if (btnText && btnPermissions && btnPermissions.length) {
const isPermission = btnPermissions.includes(btnText);
if (!isPermission) {
el.parentNode && el.parentNode.removeChild(el);
}
}
}
}

@ -0,0 +1,15 @@
/**
* 插件
* */
// 鉴权指令
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,398 @@
import axios from 'axios';
import QS from 'qs';
// import store from '../store/index'
import { Message } from 'element-ui'
import router from '@/router/index'
// 环境的切换
// if (process.env.NODE_ENV == 'development') {
// axios.defaults.baseURL = '/api';
// } else if (process.env.NODE_ENV == 'debug') {
// axios.defaults.baseURL = '';
// } else if (process.env.NODE_ENV == 'production') {
// axios.defaults.baseURL = 'http://api.123dailu.com/';
// }
// 请求超时时间
axios.defaults.timeout = 60000;
// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
axios.defaults.headers.Pragma = 'no-cache'
// 请求拦截器
// axios.interceptors.request.use(config => {
// if (sessionStorage.getItem('token')) {
// // 存在将token写入 request header
// config.headers.Authorization = `${sessionStorage.getItem('token')}`;
// }
// return config;
// }, err => {
// Message.error({
// message: '退出登陆',
// onClose: function () {
// router.push({name: 'login'});
// }
// })
// return Promise.reject(err);
// })
// 响应拦截器
// axios.interceptors.response.use(
// response => {
// consol.log(response.status)
// if (response.status === 200) {
// return Promise.resolve(response);
// } else {
// return Promise.reject(response);
// }
// },
// // 服务器状态码不是200的情况
// error => {
// if (error.response.status) {
// switch (error.response.status) {
// // 401: 未登录
// // 未登录则跳转登录页面,并携带当前页面的路径
// // 在登录成功后返回当前页面,这一步需要在登录页操作。
// case 500:
// router.replace({
// path: '/login',
// // query: { redirect: router.currentRoute.fullPath }
// });
// break;
// // 403 token过期
// // 登录过期对用户进行提示
// // 清除本地token和清空vuex中token对象
// // 跳转登录页面
// case 403:
// // Toast({
// // message: '登录过期,请重新登录',
// // duration: 1000,
// // forbidClick: true
// // });
// // 清除token
// sessionStorage.removeItem('token');
// store.commit('loginSuccess', null);
// // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
// setTimeout(() => {
// router.replace({
// path: '/login',
// query: {
// redirect: router.currentRoute.fullPath
// }
// });
// }, 1000);
// break;
// // 404请求不存在
// case 404:
// router.replace({
// path: '/404',
// });
// break;
// // 其他错误,直接抛出错误提示
// default:
// router.replace({
// path: '/500',
// });
// }
// return Promise.reject(error.response);
// }
// }
// );
/**
* get方法对应get请求
*/
export function get(url, params){
return new Promise((resolve, reject) =>{
axios.get(url, {
params: params
})
.then(res => {
if (res.data.status){
switch (res.data.status) {
case 200:
resolve(res.data);
break;
}
}else{
if (res.data.success) {
switch (res.data.code) {
case 200:
resolve(res.data);
break;
case 10000:
resolve(res.data);
break;
case 500:
this.errorMsg(
res.data.errmessage
);
break;
case 300:
this.errorMsg(
res.data.errmessage
);
break;
case 404:
this.errorMsg(
res.data.errmessage
);
break;
case 403:
this.errorMsg(
res.data.errmessage
);
break;
case 401:
Message.error("token失效,请重新登录");
sessionStorage.removeItem('token');
router.replace('/login')
break;
case 405:
this.errorMsg(
res.data.errmessage
);
break;
case 406:
this.errorMsg(
res.data.errmessage
);
break;
}
}else{
this.errorMsg(res.data.message);
}
}
})
.catch(err => {
reject(err.data)
this.$message({
showClose: true,
message: '请求失败,请刷新页面重新进行请求',
type: 'error'
});
})
});
}
/**
* post方法对应post请求
*/
export function post(url, params) {
return new Promise((resolve, reject) => {
axios.post(url,params)
.then(res => {
if (res.data.status){
switch (res.data.status) {
case 200:
resolve(res.data);
break;
}
}else{
if (res.data.success) {
switch (res.data.code) {
case 200:
resolve(res.data);
break;
case 201:
resolve(res.data);
break;
case 500:
this.errorMsg(
res.data.errmessage
);
break;
case 300:
this.errorMsg(
res.data.errmessage
);
break;
case 404:
this.errorMsg(
res.data.errmessage
);
break;
case 403:
this.errorMsg(
res.data.errmessage
);
break;
case 401:
Message.error("token失效,请重新登录");
sessionStorage.removeItem('token');
router.replace('/login')
break;
case 405:
this.errorMsg(
res.data.errmessage
);
break;
case 406:
this.errorMsg(
res.data.errmessage
);
break;
}
}else{
this.errorMsg(res.data.message);
}
}
})
.catch(err => {
reject(err.data)
this.$message({
showClose: true,
message: '请求失败,请刷新页面重新进行请求',
type: 'error'
});
})
});
}
/**
* delete方法对应delete请求
*/
export function del(url, params){
return new Promise((resolve, reject) =>{
axios.delete(url, {params})
.then(res => {
if (res.data.status){
switch (res.data.status) {
case 200:
resolve(res.data);
break;
}
}else{
if (res.data.success) {
switch (res.data.code) {
case 200:
resolve(res.data);
break;
// case 300:
// this.errorMsg(
// res.data.errmessage
// );
// break;
case 500:
this.errorMsg(
res.data.errmessage
);
break;
case 404:
this.errorMsg(
res.data.errmessage
);
router.replace({
path: '/404',
});
break;
case 403:
this.errorMsg(
res.data.errmessage
);
break;
case 401:
Message.error("token失效,请重新登录");
sessionStorage.removeItem('token');
router.replace('/login')
break;
case 405:
this.errorMsg(
res.data.errmessage
);
break;
case 406:
this.errorMsg(
res.data.errmessage
);
break;
}
}else{
this.errorMsg(res.data.message);
}
}
})
.catch(err => {
reject(err.data)
this.$message({
showClose: true,
message: '请求失败,请刷新页面重新进行请求',
type: 'error'
});
})
});
}
/**
* put修改
* @param {} url
* @param {*} params
*/
export function put(url, params){
return new Promise((resolve, reject) =>{
axios.put(url, params)
.then(res => {
if (res.data.status){
switch (res.data.status) {
case 200:
resolve(res.data);
break;
}
}else{
if (res.data.success) {
switch (res.data.code) {
case 200:
resolve(res.data);
break;
case 300:
this.errorMsg(
res.data.errmessage
);
break;
case 500:
this.errorMsg(
res.data.errmessage
);
break;
case 404:
this.errorMsg(
res.data.errmessage
);
break;
case 403:
this.errorMsg(
res.data.errmessage
);
break;
case 401:
Message.error("token失效,请重新登录");
sessionStorage.removeItem('token');
router.replace('/login')
break;
case 405:
this.errorMsg(
res.data.errmessage
);
break;
case 406:
this.errorMsg(
res.data.errmessage
);
break;
}
}else{
this.errorMsg(res.data.message);
}
}
})
.catch(err => {
reject(err.data)
this.$message({
showClose: true,
message: '请求失败,请刷新页面重新进行请求',
type: 'error'
});
})
});
}

@ -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,27 @@
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()
router.selfAddRoutes = function (params){
router.matcher = createRouter().matcher;
router.addRoutes(params)
}
export default router

@ -0,0 +1,33 @@
import router from './index';
import store from '@/store';
import Setting from '@/setting';
import generateRoutes from '@/libs/route/generateRoutes';
import bus from '@/libs/bus';
router.beforeEach((to, from, next) => {
document.title = to.meta.title ? `${to.meta.title} | ${Setting.titleSuffix}` : Setting.titleSuffix;
const role = sessionStorage.getItem(Setting.usernameKey);
if (!role && to.path !== '/login') {
next('login')
// if(to.fullPath != '/404' && to.fullPath != '/'){
// next({
// path: 'login',
// query: {redirect: to.fullPath}
// })
// }else{
// next('login')
// }
} else if(role && to.path == '/login') {
next('dashboard')
} else {
to.meta.title != '404' && store.commit('sidebarData',{sidebarMenu: to.meta.sidebar})
if(to.meta.sidebar){
bus.$emit('showMenu', true)
}else{
bus.$emit('showMenu', false)
}
next();
}
});
Setting.dynamicRoute && generateRoutes()

@ -0,0 +1,72 @@
export default [
{
path: '/',
redirect: 'login'
},
{
path: '/',
component: () => import('@/layouts/home/index.vue'),
meta: { title: '自述文件' },
children: [
{
name: 'personalcenter',
path: 'personalcenter',
component: () => import('@/pages/personalcenter.vue'),
meta: {
title: '个人中心'
}
},
{
name: 'matchDetail',
path: 'matchDetail',
component: () => import('@/pages/matchDetail.vue'),
meta: { title: '大赛简介',sidebar: 'match' }
},
{
name: 'courseSection',
path: 'courseSection',
component: () => import('@/pages/courseSection.vue'),
meta: { title: '课程预览' }
},
// {
// name: 'course',
// path: 'course',
// component: () => import('@/pages/course.vue'),
// meta: { title: '课程管理' }
// },
// {
// name: 'addcourse',
// path: 'addcourse',
// component: () => import('@/pages/addCourse.vue'),
// meta: { title: '新增课程' }
// },
{
// 国际化组件
name: 'i18n',
path: 'i18n',
component: () => import( '@/pages/i18n.vue'),
meta: { title: '国际化' }
},
{
name: '404',
path: '404',
component: () => import('@/pages/404.vue'),
meta: { title: '404' }
},
{
name: '403',
path: '403',
component: () => import('@/pages/403.vue'),
meta: { title: '403' }
}
]
},
{
name: 'login',
path: '/login',
component: () => import('@/pages/login.vue'),
meta: { title: '登录' }
},
]

@ -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;

@ -0,0 +1,116 @@
/**
* 业务配置
* */
const env = process.env.NODE_ENV;
const Setting = {
/**
* 基础配置
* */
// 网页标题的后缀
titleSuffix: '电子竞技在线教学资源管理平台-企业端',
// 路由模式,可选值为 history 或 hash
routerMode: 'hash',
// 页面切换时,是否显示模拟的进度条
showProgressBar: true,
// 接口请求地址
// apiBaseURL: env === 'development' ? 'http://192.168.31.137:8001' : 'http://8.134.8.197:8000',
apiBaseURL: env === 'development' ? 'http://8.134.8.197:8001' : 'http://8.134.8.197:8001',
// 接口请求返回错误时,弹窗的持续时间,单位:秒
modalDuration: 3,
// 接口请求返回错误时,弹窗的类型,可选值为 Message 或 Notice
errorModalType: 'Message',
// Cookies 默认保存时间,单位:天
cookiesExpires: 1,
/**
* sessionStorage里state的key
*/
storeKey: 'gz_ent_store',
/**
* sessionStorage里username的key
*/
usernameKey: 'gz_ent_username',
/**
* 默认密码
*/
initialPassword: '111aaa',
/**
* 多语言配置
* */
i18n: {
// 默认语言
default: 'zh',
// 是否根据用户电脑配置自动设置语言(仅第一次有效)
auto: false
},
/**
* 布局配置
* */
// 侧边菜单宽度,单位 px,不可动态修改,需与 setting.less 的 @menuSideWidth 保持一致
menuSideWidth: 256,
layout: {
// 需要隐藏顶栏的页面路径
hideNavList: ['matchintro','matchprogress','matchsignup','addarticle'],
// 侧边栏风格,可选值为 dark 或 light
siderTheme: 'dark',
// 顶栏风格,可选值为 light、dark 或 primary
headerTheme: 'light',
// 顶栏是否置顶,开启后会覆盖侧边栏,需开启 headerFix
headerStick: false,
// 是否开启多 Tabs 页签
tabs: true,
// 多 Tabs 页签是否显示图标,开启 tabs 时有效
showTabsIcon: true,
// 是否固定多 Tabs 多页签
tabsFix: true,
// 是否固定侧边栏
siderFix: true,
// 是否固定顶栏
headerFix: true,
// 是否在下滑时隐藏顶栏,需开启 headerFix,如果开启了 tabsFix,Tabs 也会被隐藏
headerHide: false,
// 是否显示顶部菜单栏
// 一般来说,侧边的菜单栏足以满足大部分业务,如需动态切换侧边栏,可开启此选项启用顶部一级菜单,此时侧边栏将作为二级菜单
headerMenu: false,
// 侧边菜单栏是否开启手风琴模式
menuAccordion: true,
// 是否显示折叠侧边栏按钮,移动端下会自动强制开启
showSiderCollapse: true,
// 侧边菜单栏是否默认折起
menuCollapse: false,
// 侧边菜单折起时,是否在子菜单前显示父级菜单名称
showCollapseMenuTitle: false,
// 是否显示重载按钮
showReload: true,
// 是否显示搜索
showSearch: true,
// 是否显示通知
showNotice: true,
// 是否显示全屏
showFullscreen: true,
// 在手机访问时,是否在顶部显示小尺寸 logo
showMobileLogo: true,
// 是否显示全局面包屑,开启 headerMenu 时不可用
showBreadcrumb: true,
// 全局面包屑是否显示图标,开启 showBreadcrumb 时有效
showBreadcrumbIcon: false,
// 是否显示日志入口,开启与否,不影响日志记录,如不希望用户看到可关闭
showLog: true,
// 是否显示多语言
showI18n: true,
// 是否支持动态修改布局配置,移动端下会自动强制关闭
enableSetting: true,
// 退出登录时,是否二次确认
logoutConfirm: true
},
/**
* 功能配置
* */
// 相同路由,不同参数间进行切换,是否强力更新
sameRouteForceUpdate: false,
// 是否使用动态路由
dynamicRoute: true
};
export default Setting;

@ -0,0 +1,85 @@
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
customerId:'',
courseId:'',
userId: '',
roleId: '',
manager:{},
provinceList: [],
configId: '',
systemId: '',
orderId: '',
userLoginId: '',
accountRole: '',
name:'',
account:'',
phone:'',
schoolId: '',
schoolName: '',
routes: [],
btnPermissions: [],
indexPath: '',
sidebarMenu: false,
matchId: '',
},
mutations:{
userData (state, payload) {
state.userId = payload.user_id,
state.roleId = payload.roleId
},
customerData (state, payload) {
state.customerId = payload.customer_id
},
courseData (state, payload) {
state.courseId = payload.course_id
},
managerData (state, payload) {
state.manager = payload.form
},
provinceData (state, payload) {
state.provinceList = payload.provinceList
},
configData (state, payload) {
state.configId = payload.config_id
},
systemData (state, payload) {
state.systemId = payload.system_id
state.orderId = payload.order_id
},
setAvatarData (state, payload) {
state.avatar = payload.avatar
},
userLoginData (state, payload) {
state.userLoginId = payload.userId
state.accountRole = payload.accountRole
},
userInfo(state,payload){
state.name = payload.name
state.account = payload.account
state.phone = payload.phone
state.schoolId = payload.schoolId
state.schoolName = payload.schoolName
},
sidebarData (state, payload) {
state.sidebarMenu = payload.sidebarMenu
},
matchData (state, payload) {
state.matchId = payload.matchId
},
addRoutesData (state, payload) {
state.routes = payload.routes
},
addBtnPerData (state, payload) {
state.btnPermissions = payload.btnPermissions
},
addIndex (state, payload) {
state.indexPath = payload.path
}
}
});
export default store;

@ -0,0 +1,359 @@
@import "./default/index.scss";
@font-face{
font-family: youshe;
src: url('font/YouSheBiaoTiHei.ttf');
}
[v-cloak] {
display: none;
}
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0.06);
}
.required{
font-size: 16px;
color: #CC221C;
font-style: normal;
}
.breadcrumb{
display: flex;
align-items: center;
margin-bottom: 20px;
.cur,.el-breadcrumb__inner,.el-breadcrumb__separator{
color: rgba(0,0,0,.45) !important;
font-weight: 400 !important;
font-size: 12px;
}
.el-breadcrumb__item:last-of-type .el-breadcrumb__inner{
color: rgba(0,0,0,.85) !important;
}
}
.el-button--primary.action-btn{
color: #CC221C !important;
font-size: 14px !important;
background-color: #fff !important;
border-radius: 4px !important;
}
.el-input{
.el-input__inner{
border-color: rgba(0, 0, 0, 0.15);
}
}
.page{
position: relative;
background-color: #fff;
border-radius: 8px;
.p-title{
padding-left: 24px;
line-height: 56px;
font-size: 16px;
color: rgba(0, 0, 0, 0.85);
border-bottom: 1px solid rgba(0,0,0,.06);
}
.page-content{
padding: 24px;
.tool{
display: flex;
justify-content: space-between;
margin-bottom: 24px;
.filter{
display: inline-flex;
align-items: center;
flex: 1;
li{
display: inline-flex;
align-items: center;
margin-right: 30px;
label{
font-size: 14px;
line-height: 14px;
color: rgba(0,0,0,.65);
white-space: nowrap;
}
}
}
.single-choice{
dl {
display: flex;
line-height: 30px;
dt {
color: rgba(0,0,0,.65);
font-size: 14px;
white-space: nowrap;
}
dd {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
span {
padding: 0 10px;
margin: 0 10px;
color: #333;
font-size: 14px;
line-height: 1.8;
white-space: nowrap;
cursor: pointer;
&:hover {
color: #CC221C;
}
&.active {
border-radius: 4px;
color: #fff;
background-color: #CC221C;
}
}
}
}
}
.el-button--primary{
@extend .action-btn;
}
}
}
}
.pagination {
margin: 20px 0;
text-align: center;
button,.number{
color: rgba(0,0,0,.65) !important;
background-color: transparent !important;
border: 1px solid rgba(0, 0, 0, 0.15) !important;
border-radius: 4px !important;
}
button i{
color: #333;
}
.active{
color: #fff !important;
background-color: #CC221C !important;
}
}
.el-table{
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.06);
border-bottom: 0;
.cell{
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
.el-checkbox{
&:before{
content: '全选';
margin-right: 5px;
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
opacity: 0;
}
}
}
th{
background: rgba(0, 0, 0, 0.04)!important;
font-size: 14px;
color: rgba(0, 0, 0, 0.85);
font-weight: normal;
.cell{
.el-checkbox{
&:before{
opacity: 1;
}
}
}
}
.el-checkbox__inner{
border-radius: 4px;
transition: none !important;
}
.el-checkbox__input.is-indeterminate .el-checkbox__inner{
background-color: #FFFFFF;
border-color: #DCDFE6;
}
.el-switch__core{
background-color: #bfbfbf;
}
.el-switch__label--right{
z-index: 2;
position: absolute;
right: 8px;
margin-left: 0;
color: #fff !important;
}
.el-switch__label--right.is-active{
left: 8px;
right: auto;
}
.el-switch__label--right span{
font-size: 12px;
}
}
.tabs{
display: flex;
align-items: center;
padding: 0 24px;
margin-bottom: 20px;
border-bottom: 1px solid rgba(0,0,0,.06);
.item{
position: relative;
padding: 20px 0;
margin-right: 40px;
font-size: 16px;
color: rgba(0, 0, 0, 0.65);
cursor: pointer;
&:after{
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 3px;
border-bottom: 3px solid transparent;
border-radius: 2px;
}
&.active{
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
}
&.active:after{
border-bottom-color: $--color-primary;
}
}
}
.el-message{
padding: 11px 20px;
.el-message__icon{
font-size: 16px;
}
.el-message__content{
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
}
.el-icon-close{
font-size: 14px;
color: #92998d;
}
.el-message--success{
border: 1px solid #B7EB8F;
background: #F6FFED;
.el-message__icon{
color: #00c700;
}
}
.el-message--warning{
border: 1px solid #FFE58F;
background: #FFFBE6;
.el-message__icon{
color: #ffa900;
}
}
}
.el-message-box{
padding-bottom: 24px;
.el-message-box__header{
padding: 32px 32px 12px 50px;
span{
font-size: 16px;
color: rgba(0, 0, 0, 0.85);
font-weight: 500;
}
}
.el-message-box__status{
top: -30px;
}
.el-message-box__status + .el-message-box__message{
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
}
.el-message-box__btns{
padding-right: 32px;
&.el-icon-warning{
color: #ffa900;
}
}
.el-button--primary,.el-button--primary:hover, .el-button--primary:focus{
background: #CC221C;
}
}
.el-dialog__wrapper{
.el-dialog{
border-radius: 4px;
.el-dialog__header{
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
.el-dialog__title{
font-size: 16px;
color: rgba(0, 0, 0, 0.85);
}
}
.el-dialog__footer{
padding: 10px 16px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
.el-button{
font-size: 14px;
border-radius: 4px;
border-color: rgba(0, 0, 0, 0.15);
}
}
}
}
.upload-wrap{
position: relative;
display: flex;
justify-content: center;
align-items: center;
padding: 34px 0;
.el-button{
span{
display: flex;
align-items: center;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
img{
margin-right: 8px;
}
}
}
&>.el-button{
margin-right: 32px;
}
.el-upload-list{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
.link{
position: absolute;
bottom: -20px;
left: 0;
width: 100%;
text-align: center;
}
&.lg{
padding-bottom: 50px;
}
}
@media(max-width: 1600px){
.el-table{
.el-switch__label--right.is-active{
left: 8px;
}
}
}

@ -0,0 +1,7 @@
/* 改变主题色变量 */
$--color-primary: #CC221C;
/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";

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

Loading…
Cancel
Save