ui1
yujialong 4 years ago
commit 834fb22228
  1. 3
      .browserslistrc
  2. 22
      .gitignore
  3. 6
      .prettierrc
  4. 21
      LICENSE
  5. 5
      babel.config.js
  6. 13485
      package-lock.json
  7. 38
      package.json
  8. 5
      postcss.config.js
  9. 18
      public/index.html
  10. 24
      src/App.vue
  11. 57
      src/api/index.js
  12. BIN
      src/assets/img/account.png
  13. BIN
      src/assets/img/download.png
  14. BIN
      src/assets/img/login-bg.png
  15. BIN
      src/assets/img/logo.png
  16. BIN
      src/assets/img/password.png
  17. BIN
      src/assets/img/remove.png
  18. BIN
      src/assets/img/search-white.png
  19. BIN
      src/assets/img/search.png
  20. BIN
      src/assets/img/stat1.png
  21. BIN
      src/assets/img/stat2.png
  22. BIN
      src/assets/img/stat3.png
  23. BIN
      src/assets/img/stat4.png
  24. BIN
      src/assets/img/three.png
  25. BIN
      src/assets/img/upload.png
  26. BIN
      src/assets/img/user.png
  27. 30
      src/components/breadcrumb/index.vue
  28. 124
      src/components/pdf/index.vue
  29. 179
      src/components/quill/index.vue
  30. 16
      src/components/quill/options.js
  31. 30
      src/i18n/index.js
  32. 28
      src/layouts/footer/index.vue
  33. 102
      src/layouts/header/index.vue
  34. 68
      src/layouts/home/index.vue
  35. 105
      src/layouts/navbar/index.vue
  36. 186
      src/layouts/tags/index.vue
  37. 25
      src/libs/auth/generateBtnPermission.js
  38. 6
      src/libs/bus.js
  39. 10
      src/libs/random_str.js
  40. 16
      src/libs/resize/index.js
  41. 34
      src/libs/route/addRoutes.js
  42. 26
      src/libs/route/generateRoutes.js
  43. 6
      src/libs/route/resetRouter.js
  44. 43
      src/libs/util.cookies.js
  45. 82
      src/libs/util.db.js
  46. 121
      src/libs/util.js
  47. 45
      src/main.js
  48. 11
      src/mixins/app.js
  49. 8
      src/mixins/setBackground/index.js
  50. 176
      src/pages/account/login/index.vue
  51. 285
      src/pages/data/list/index.vue
  52. 59
      src/pages/exception/error/403/index.vue
  53. 59
      src/pages/exception/error/404/index.vue
  54. 46
      src/pages/exception/i18n/index.vue
  55. 225
      src/pages/exception/icon/index.vue
  56. 70
      src/pages/index/list/index.vue
  57. 295
      src/pages/role/list/index.vue
  58. 108
      src/pages/setting/person/download.vue
  59. 100
      src/pages/setting/person/index.vue
  60. 551
      src/pages/setting/person/info.vue
  61. 250
      src/pages/stat/list/index.vue
  62. 627
      src/pages/user/list/index.vue
  63. 1
      src/plugins/aliplayer/aliplayer-min.css
  64. 2
      src/plugins/aliplayer/aliplayer-min.js
  65. 25
      src/plugins/auth/index.js
  66. 12
      src/plugins/filters/index.js
  67. 14
      src/plugins/index.js
  68. 161
      src/plugins/requests/index.js
  69. 18
      src/plugins/throttle/index.js
  70. 22
      src/router/index.js
  71. 23
      src/router/modules/data.js
  72. 23
      src/router/modules/index.js
  73. 23
      src/router/modules/role.js
  74. 23
      src/router/modules/setting.js
  75. 23
      src/router/modules/stat.js
  76. 23
      src/router/modules/user.js
  77. 28
      src/router/modules/wrongBook.js
  78. 15
      src/router/permission.js
  79. 76
      src/router/routes.js
  80. 21
      src/setting.env.js
  81. 68
      src/setting.js
  82. 10
      src/store/getters.js
  83. 25
      src/store/index.js
  84. 32
      src/store/modules/achievement.js
  85. 19
      src/store/modules/client.js
  86. 24
      src/store/modules/common.js
  87. 97
      src/store/modules/exam.js
  88. 24
      src/store/modules/layout.js
  89. 47
      src/store/modules/practice.js
  90. 108
      src/store/modules/user.js
  91. 24
      src/store/modules/wrongBook.js
  92. 373
      src/styles/common.scss
  93. 7
      src/styles/default/index.scss
  94. BIN
      src/styles/font/YouSheBiaoTiHei.ttf
  95. 539
      src/styles/font/icon/demo.css
  96. 446
      src/styles/font/icon/demo_index.html
  97. 71
      src/styles/font/icon/iconfont.css
  98. BIN
      src/styles/font/icon/iconfont.eot
  99. 1
      src/styles/font/icon/iconfont.js
  100. 93
      src/styles/font/icon/iconfont.json
  101. Some files were not shown because too many files have changed in this diff Show More

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

22
.gitignore vendored

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

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

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

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

13485
package-lock.json generated

File diff suppressed because it is too large Load Diff

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

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

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

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

@ -0,0 +1,57 @@
import Setting from '@/setting'
let uploadURL = Setting.upload.apiURL
export default {
// 登录注册
logins: `management/userInfo/login`,
save: `management/userInfo/add`,
uploadUserAvatars: `liuwanr/userInfo/uploadUserAvatars`,
queryProvince: `liuwanr/province/queryProvince`,
queryCity: `liuwanr/city/queryCity`,
querySchoolData: `liuwanr/customer/querySchool`,
queryAccountIsExist:`liuwanr/userInfo/queryAccountIsExist`,
queryWorkNumberIsExist:`evaluation/tms/userInfo/queryWorkNumberIsExist`,
queryStaffWorkNumberIsExist:`evaluation/tms/system/queryStaffWorkNumberIsExist`,
querySchool: `liuwanr/customer/querySchool`,
// 个人中心
userinfo:`evaluation/tms/userInfo/userinfo`,
userinfoUpdate:`evaluation/tms/userInfo/updateUser`,
sendEmailCode:`evaluation/tms/user/sendEmailCode`,//发送邮箱验证码
bingEmail:`evaluation/tms/user/bingEmail`,//邮箱验证并更新
sendPhoneCode:`evaluation/tms/user/sendPhoneCode`,//发送手机验证码
bindPhone:`evaluation/tms/user/bindPhone`,//校验手机验证码
// oss文件管理
fileDeletion: `${uploadURL}/oss/manage/fileDeletion`,
fileupload: `${uploadURL}/oss/manage/fileupload`,
getPlayAuth: `${uploadURL}/oss/manage/getPlayAuth`,
removeMoreVideo: `${uploadURL}/oss/manage/removeMoreVideo`,
removeVideo: `${uploadURL}/oss/manage/removeVideo`,
//查询电话是否存在
queryProvince: `cjEnterprise/province/queryProvince`,
queryCity: `cjEnterprise/city/queryCity`,
queryClient: `cjEnterprise/client/list`,
// 员工管理
addStaff: `evaluation/tms/system/addStaff`,
daleteBatchStaff: `evaluation/tms/system/daleteBatchStaff`,
queryStaff: `evaluation/tms/system/queryStaff`,
querystaffDetail: `evaluation/tms/system/querystaffDetail`,
updateStaff: `evaluation/tms/system/updateStaff`,
downloadStaff: `evaluation/tms/system/download`,
export_failureStaff: `evaluation/tms/system/export_failure`,
uploadFileStaff: `evaluation/tms/system/uploadFile`,
queryAccountStaff:`evaluation/tms/system/queryAccount`,
resetPwd:`evaluation/tms/system/resetPwd`,
// 角色权限
rolePermissionList:`evaluation/sys-permission/rolePermissionList`,
saveRolePermission:`evaluation/sys-permission/saveRolePermission`,
updateRolePermission:`evaluation/sys-permission/updateRolePermission`,
delRolePermission:`evaluation/sys-permission/delRolePermission`,
queryPermissionArrById:`evaluation/sys-permission/queryPermissionArrById`,
roleTree:`evaluation/sys-permission/tree`,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 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 : path }">{{item}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script>
export default {
props: ['data','route'],
data() {
return {
pages: this.data.split('/'),
curRoute: this.$route.path,
path: this.route ? this.route : 'list'
};
},
methods: {
update(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: ''
},
readonly: {
type: Boolean,
default: false
},
toTop: {
type: Boolean,
default: true
},
border: {
type: Boolean,
default: false
},
height: {
type: Number
},
minHeight: {
type: Number
}
},
data () {
return {
Quill: null,
currentValue: '',
options: {
theme: 'snow',
bounds: document.body,
debug: 'warn',
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
'image': function (value) {
if (value) {
// iview
document.querySelector('.editorUpload').click()
} else {
this.Quill.format('image', false);
}
}
}
}
},
placeholder: '',
readOnly: this.readonly
},
loading: false
}
},
computed: {
classes () {
return [
{
'quill-no-border': !this.border
}
];
},
styles () {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
}
},
watch: {
value: {
handler (val) {
if (val !== this.currentValue) {
this.currentValue = val;
if (this.Quill) {
this.Quill.pasteHTML(this.value);
}
}
},
immediate: true
}
},
mounted () {
this.init();
},
beforeDestroy () {
//
this.Quill = null;
},
methods: {
init () {
const editor = this.$refs.editor;
//
this.Quill = new Quill(editor, this.options);
//
this.Quill.pasteHTML(this.currentValue);
if(this.toTop){
this.$nextTick(() => {
window.scrollTo(0,0)
})
}
//
this.Quill.on('text-change', (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText();
const quill = this.Quill;
//
this.currentValue = html;
// v-model
this.$emit('input', html);
//
this.$emit('on-change', { html, text, quill });
});
// quill
this.Quill.on('text-change', (delta, oldDelta, source) => {
this.$emit('on-text-change', delta, oldDelta, source);
});
this.Quill.on('selection-change', (range, oldRange, source) => {
this.$emit('on-selection-change', range, oldRange, source);
});
this.Quill.on('editor-change', (eventName, ...args) => {
this.$emit('on-editor-change', eventName, ...args);
});
},
beforeUpload(file){
this.loading = true
},
editorUploadSuccess (res) {
//
let quill = this.Quill
//
if (res.data.filesResult.fileUrl) {
//
let length = quill.getSelection().index;
// res
quill.insertEmbed(length, 'image', res.data.filesResult.fileUrl)
//
quill.setSelection(length + 1)
} else {
this.$message.success('图片插入失败')
}
this.loading = false
},
}
}
</script>
<style lang="scss" scoped>
.quill-no-border{
.ql-toolbar.ql-snow{
border: none;
border-bottom: 1px solid #e8eaec;
}
.ql-container.ql-snow{
border: none;
}
}
</style>

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

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

@ -0,0 +1,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,102 @@
<template>
<div class="header">
<div class="inner">
<img class="logo" src="../../assets/img/logo.png" alt="">
<div style="height: 80px;"></div>
<navbar></navbar>
<div class="action">
<img class="search" src="../../assets/img/search.png" alt="">
<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="person">个人资料</el-dropdown-item>
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
</template>
<script>
import navbar from '../navbar'
import { mapState,mapActions } from 'vuex'
import Setting from '@/setting'
export default {
data() {
return {
showBackList: Setting.layout.hideNavList,
};
},
components: { navbar },
computed: {
...mapState('user', [
'userId','avatar','userName'
]),
showBack(){
let route = this.$route.name
if(this.showBackList.includes(route)) return true
return false
}
},
mounted(){
},
methods: {
...mapActions('user', [
'logout'
]),
userCommand(command){
console.log(command)
if(command == 'person'){
this.$router.push('/setting/person')
}else{
this.logout()
}
}
},
};
</script>
<style lang="scss" scoped>
.header{
position: relative;
height: 80px;
background-color: #fff;
.inner{
display: flex;
justify-content: space-between;
align-items: center;
width: $inner-width;
margin: 0 auto;
}
.logo{
width: 180px;
}
.action{
display: inline-flex;
align-items: center;
.search{
margin-right: 30px;
cursor: pointer;
}
.user-wrap {
display: inline-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,68 @@
<template>
<div class="main">
<v-head></v-head>
<div class="layout">
<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'
import vFooter from '../footer'
import bus from '@/libs/bus'
import Setting from '@/setting'
export default {
data() {
return {
tagsList: [],
collapse: false,
hideNavList: Setting.layout.hideNavList
};
},
components: {
vHead,
vFooter
},
computed: {
hideNavbar() {
let route = this.$route.name
if(this.hideNavList.includes(route)) return false
return true
}
},
created() {
bus.$on('collapse-content', msg => {
this.collapse = msg;
});
// 使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{
min-height: 100%;
background: url(../../assets/img/login-bg.png) 0 0/100% 100% no-repeat;
.view{
width: $inner-width;
padding: 20px 0;
margin: 0 auto;
}
}
</style>

@ -0,0 +1,105 @@
<template>
<div>
<ul class="nav">
<li v-for="(item,index) in menus" :key="index" :class="{active: active == item.index}" @click="jump(item)">{{item.title}}</li>
</ul>
</div>
</template>
<script>
import { mapState } from 'vuex'
import bus from '@/libs/bus'
import Setting from '@/setting'
export default {
data() {
return {
active: this.$route.path,
defaultMenus: [
{
index: '/index/list',
title: '首页'
},{
index: '/data/list',
title: '数据'
},{
index: '/stat/list',
title: '数据统计'
},{
index: '/user/list',
title: '用户管理'
},{
index: '/role/list',
title: '角色权限'
},
],
menus: [],
actives: {
practice: ['practice-do','practice-randomDo'],
exam: ['exam-do'],
achievement: ['achievement-practice','achievement-assessment'],
wrongBook: ['wrongBook-do'],
}
};
},
computed: {
onRoutes() {
let actives = this.actives
for(let i in this.actives){
if(actives[i].includes(this.$route.name)) return `/${i}/list`
}
return this.$route.path
},
...mapState('auth', [
'routes'
])
},
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.routes
let menus = []
this.defaultMenus.map(e => {
routes.find(n => n.path == e.index) && menus.push(e)
})
this.menus = menus
this.active = menus[0].index
}else{
this.menus = this.defaultMenus
}
},
jump(item){
this.active = item.index
this.$router.push(item.index)
}
}
};
</script>
<style lang="scss" scoped>
.nav{
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
padding-bottom: 10px;
li{
padding: 25px;
font-size: 16px;
color: #0d0d0d;
cursor: pointer;
&.active{
color: #fff;
background-color: #568df2;
}
}
}
</style>

@ -0,0 +1,186 @@
<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('/');
}
},
//
closeAll(){
this.tagsList = [];
this.$router.push('/');
},
//
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>
.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,10 @@
// 生成随机字符串
export default function (len = 32) {
const $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
const maxPos = $chars.length;
let str = '';
for (let i = 0; i < len; i++) {
str += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return str;
}

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

@ -0,0 +1,34 @@
import store from '@/store';
import router from '@/router';
import generateBtnPermission from '../auth/generateBtnPermission';
const newRoutes = []
function createMeta(item){
let meta = { title: item.name }
return meta
}
function createRoute(data){
data.map(e => {
if(e.select && e.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)
}

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

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

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

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

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

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

@ -0,0 +1,176 @@
<template>
<div class="wrap">
<vHead></vHead>
<div class="login">
<div class="names">
<img class="logo" src="../../../assets/img/three.png" alt="">
<p class="text">或然数据网</p>
</div>
<div class="form">
<div class="title"><span>登录</span></div>
<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>
<div class="check">
<el-checkbox v-model="remember">15天免费登录</el-checkbox>
</div>
<el-button class="submit" type="primary" @click="submitForm">登录</el-button>
</el-form>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import vHead from '@/layouts/header'
export default {
data: function() {
return {
loginForm: {
username: '20204400194',
password: '111aaa',
},
loginRules: {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
},
remember: false
};
},
components: {vHead},
methods: {
...mapActions('user', [
'login'
]),
submitForm() {
this.$refs.login.validate(valid => {
if (valid) {
let data = {
username: this.loginForm.username,
password: this.loginForm.password
}
this.login(data).then(() => {
let redirect = this.$route.query.redirect ? decodeURIComponent(this.$route.query.redirect) : '/index'
this.$router.replace(redirect)
}).catch(() => {})
}
})
},
},
};
</script>
<style scoped lang="scss">
.wrap {
min-height: 100%;
background: url(../../../assets/img/login-bg.png) 0 0/100% 100% no-repeat;
overflow: hidden;
.login{
width: 500px;
margin: 0 auto;
text-align: center;
.names{
margin: 70px 0;
.text{
margin-top: 10px;
font-size: 20px;
color: #fff;
}
}
.form{
padding: 30px;
margin-top: 30px;
border-radius: 10px;
background-color: #fff;
.title{
position: relative;
margin-bottom: 30px;
text-align: center;
span{
display: inline-block;
padding: 9px 20px;
color: #555;
border-bottom: 2px solid $main-color;
}
&:after{
content: '';
position: absolute;
left: 0;
bottom: -1px;
width: 100%;
height: 1px;
background-color: #e0e0e0;
}
}
.el-form{
padding: 0 70px;
}
.label{
margin-bottom: 10px;
color: #105CB2;
}
/deep/.el-input__inner{
position: relative;
height: 46px;
padding: 0 20px 0 40px;
line-height: 46px;
border: 0;
border-bottom: 1px solid #e4e4e4;
border-radius: 0 !important;
}
.account,.password{
z-index: 10;
position: absolute;
top: 11px;
left: 8px;
width: 24px;
height: 28px;
background: url(../../../assets/img/account.png) 0 0/100% 100% no-repeat;
}
.password{
width: 22px;
height: 24px;
background-image: url(../../../assets/img/password.png);
}
.check{
text-align: left;
}
/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: $main-color;
border-radius: 8px;
border: 0;
}
.links{
margin: 20px 0 20px;
}
.login-tips{
margin-bottom: 20px;
font-size: 16px;
color: #105CB2;
text-align: center;
}
}
}
}
</style>

@ -0,0 +1,285 @@
<template>
<div class="wrap">
<div class="left">
<el-menu class="menu" @open="handleOpen" @close="handleClose" :default-active="active">
<template v-for="item in typeList">
<!-- 如果第一层有子菜单则继续循环 -->
<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>
<div class="right">
<div class="block">
<h6 class="title">数据介绍</h6>
<div class="desc">
测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
</div>
<el-table :data="listData" class="table" stripe header-align="center" row-key="id">
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column prop="practiseName" label="数据表名称" align="center"></el-table-column>
<el-table-column prop="paperName" label="数据总量" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="数据大小" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="更新时间" align="center"></el-table-column>
<el-table-column label="操作" width="220" align="center">
<template slot-scope="scope">
<el-button type="text" @click="preview(scope.row)">预览</el-button>
<el-button type="text" @click="download(scope.row)">下载</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="handleCurrentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
</div>
<div class="block">
<h6 class="title">数据预览</h6>
<el-table :data="previewData" class="table" stripe header-align="center" row-key="id">
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column prop="practiseName" label="代码" align="center"></el-table-column>
<el-table-column prop="paperName" label="名称" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="最新价" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="涨跌额" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="涨跌幅" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="今开" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="最高" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="最低" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="昨结" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="成交量" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="成交额" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="买盘(外盘)" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="买盘(内盘)" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="持仓量" align="center"></el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="handlePreviewCurrentChange" :current-page="pagePreview" layout="total, prev, pager, next" :total="totalPreview"></el-pagination>
</div>
</div>
</div>
<el-dialog title="下载" :visible.sync="downloadVisible" width="540px" @close="closeDownload" :close-on-click-modal="false">
<el-form ref="form" label-width="100px" label-suffix="">
<el-form-item label="数据筛选">
<div class="checkboxs">
<el-checkbox-group v-model="field">
<el-checkbox v-for="(item,index) in fieldList" :key="index" :label="item.name"></el-checkbox>
</el-checkbox-group>
</div>
</el-form-item>
<el-form-item label="开始时间">
<el-date-picker v-model="startTime" type="date" placeholder="请选择开始时间" size="small"></el-date-picker>
</el-form-item>
<el-form-item label="结束时间">
<el-date-picker v-model="endTime" type="date" placeholder="请选择结束时间" size="small"></el-date-picker>
</el-form-item>
<el-form-item label="数据频率">
<el-select v-model="frequency" placeholder="请选择数据频率" size="small">
<el-option v-for="(item,index) in frequencyList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="downloadVisible = false">取消</el-button>
<el-button size="small" type="primary" @click="confirmDown">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
typeList: [
{
icon: 'menu-icon icon-index',
index: '1',
title: '股票数据'
},{
icon: 'menu-icon icon-index',
index: '2',
title: '期货数据',
},
],
active: '1',
listData: [
{}
],
page: 1,
pageSize: 10,
total: 0,
previewData: [],
pagePreview: 1,
pageSizePreview: 10,
totalPreview: 0,
downloadVisible: false,
field: [],
startTime: '',
endTime: '',
frequency: '',
frequencyList: [
{
id: 1,
name: '日频'
},{
id: 2,
name: '周频'
},{
id: 3,
name: '月频'
},{
id: 4,
name: '季频'
},{
id: 5,
name: '年频'
},
],
fieldList: [
{
id: 1,
name: '代码'
},{
id: 2,
name: '名称'
}
],
}
},
mounted() {
},
methods: {
getData(){
},
handleCurrentChange(val) {
this.page = val
this.$refs.table.clearSelection()
this.getData()
},
handlePreviewCurrentChange(val) {
this.pagePreview = val
this.$refs.table.clearSelection()
this.getData()
},
preview(row){
},
download(row){
this.downloadVisible = true
},
closeDownload(){
},
handleOpen(){
},
handleClose(){
},
confirmDown(){
}
}
};
</script>
<style lang="scss" scoped>
.wrap{
display: flex;
.left{
margin-right: 20px;
.menu{
width: 200px;
padding: 10px 0;
border-radius: 8px;
overflow: hidden;
.el-menu-item.is-active{
color: #fff;
background-color: $main-color;
}
}
}
.block{
padding: 34px;
margin-bottom: 20px;
background-color: #fff;
border-radius: 8px;
.title{
padding-left: 11px;
margin-bottom: 20px;
font-size: 17px;
color: $main-color;
line-height: 1.8;
border-left: 6px solid;
}
.desc{
margin-bottom: 30px;
color: #333;
}
}
}
</style>

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

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

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

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

@ -0,0 +1,70 @@
<template>
<div>
<div class="title">欢迎来到<br>或然数据网</div>
<div class="search">
<div class="input">
<img src="../../../assets/img/search-white.png" alt="">
<input type="text" placeholder="请输入关键词">
</div>
<img src="../../../assets/img/remove.png" alt="" class="remove">
</div>
</div>
</template>
<script>
export default {
name: 'index',
data() {
return {
}
},
mounted() {
},
methods: {
}
};
</script>
<style lang="scss" scoped>
.title{
margin: 70px 0 130px;
font-size: 50px;
color: #fff;
text-align: center;
}
.search{
display: flex;
justify-content: space-between;
align-items: center;
width: 930px;
padding: 7px 20px;
margin: 0 auto;
border-bottom: 2px solid #fff;
.input{
display: inline-flex;
align-items: center;
}
input{
padding-left: 20px;
margin-left: 30px;
font-size: 24px;
color: #fff;
background-color: transparent;
border: 0;
border-left: 2px solid #fff;
&::-webkit-input-placeholder{color: #fff}
&::-moz-placeholder{color: #fff}
&:-moz-placeholder{color: #fff}
&:focus{
outline: none;
}
}
.remove{
cursor: pointer;
}
}
</style>

@ -0,0 +1,295 @@
<template>
<div>
<div class="page">
<div class="page-content">
<div class="tool">
<ul class="filter">
<li>
<label>搜索</label>
<el-input 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="addRole" v-auth="'/system/list:角色权限:新增角色'">新增角色</el-button>
<el-button type="primary" size="small" round @click="delAllSelection" v-auth="'/system/list:角色权限:批量删除'">批量删除</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/list:角色权限:查看'">查看</el-button>
<template v-if="scope.row.id != 1">
<el-button type="text" @click="editRole(scope.row)" v-auth="'/system/list:角色权限:编辑'">编辑</el-button>
<el-button type="text" @click="handleDelete(scope.row)" v-auth="'/system/list:角色权限:删除'">删除</el-button>
</template>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total">
</el-pagination>
</div>
<el-dialog :title="isDetail ? '查看角色' : (isAdd ? '新增角色' : '编辑角色')" :visible.sync="roleVisible" width="500px" @close="closeRole" class="dialog" :close-on-click-modal="false">
<el-form ref="form" :model="form" label-width="100px" label-suffix="" :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>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import util from '@/libs/util'
export default {
name: 'role',
data() {
return {
keyword: '',
form: {
roleName : '',
remark : '',
id: ''
},
isDetail: false,
roleData:[],
defaultProps: {
children: 'children',
label: 'name'
},
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
importVisible: false,
isAdd: true,
roleVisible: false,
searchTimer: null,
permissions: [],
checkedIds: []
};
},
computed: {
...mapState('user', [
'userId','clientId'
])
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},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.page}/${this.pageSize}`,data).then(res => {
this.roleData = res.data.items
this.total = res.data.total
if(!this.roleData.length && this.total){
this.page--
this.getData()
}
}).catch(res => {});
},
initData(){
this.page = 1
this.getData()
},
closeRole(){
this.isDetail = false
this.form = {
roleName : '',
remark : '',
id: ''
}
this.checkedIds = []
this.permissions = []
},
currentChange(val) {
this.page = val
this.$refs.table.clearSelection()
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 util.warningMsg('请填写角色名称')
if(!this.form.remark) return util.warningMsg('请填写角色描述')
// if(!this.$refs.per.getCheckedKeys().length) return util.warningMsg('')
let roleData = {
clientId: this.clientId,
id: this.form.id,
roleName: this.form.roleName,
remark: this.form.remark,
isPort: 2
}
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: 2
}
let perRes = await this.$post(this.api.doAssign,perData)
if(perRes.success){
util.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){
util.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(`此批量删除操作不可逆,是否确认删除${util.ellipsisStr(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()
util.successMsg('删除成功')
this.getData()
}
}).catch(res => {})
}).catch(() => {});
}else{
util.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: 400px;
overflow: auto;
}
</style>

@ -0,0 +1,108 @@
<template>
<div>
<div class="block">
<ul class="filter m-b-20">
<li>
<label>搜索</label>
<el-input placeholder="请输入名称" v-model="keyword" suffix-icon="el-icon-search" clearable size="small"></el-input>
</li>
</ul>
<el-table :data="listData" class="table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange">
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column prop="roleName" label="数据名称" align="center"></el-table-column>
<el-table-column prop="roleName" label="数据表名称" align="center"></el-table-column>
<el-table-column prop="roleName" label="数据总量" align="center"></el-table-column>
<el-table-column prop="roleName" label="数据大小" align="center"></el-table-column>
<el-table-column prop="roleName" label="更新时间" align="center"></el-table-column>
<el-table-column prop="roleName" label="下载时间" align="center"></el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button type="text" @click="showRole(scope.row)">再次下载</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import util from '@/libs/util'
export default {
name: 'role',
data() {
return {
keyword: '',
searchTimer: null,
isDetail: false,
listData:[],
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
};
},
computed: {
...mapState('user', [
'userId','clientId'
])
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},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.page}/${this.pageSize}`,data).then(res => {
this.listData = res.data.items
this.total = res.data.total
if(!this.listData.length && this.total){
this.page--
this.getData()
}
}).catch(res => {});
},
initData(){
this.page = 1
this.getData()
},
handleSelectionChange(val) {
this.multipleSelection = val
},
}
};
</script>
<style lang="scss" scoped>
.block{
padding: 34px;
margin-bottom: 20px;
background-color: #fff;
border-radius: 8px;
.title{
padding-left: 11px;
margin-bottom: 20px;
font-size: 17px;
color: $main-color;
line-height: 1.8;
border-left: 6px solid;
}
}
</style>

@ -0,0 +1,100 @@
<template>
<div>
<div class="wrap">
<div class="left">
<div class="inner">
<div class="text-center">
<img :src="avatar" class="avatar" />
<el-upload :action="this.api.fileupload" :data="{userId: this.userId}" name="file" :limit="1" :on-success="changeAvatar">
<el-button type="text" size="small">上传头像</el-button>
</el-upload>
</div>
<el-menu class="menu" :default-active="active" @select="handleSelect">
<el-menu-item v-for="item in typeList" :index="item.index" :key="item.index">
<i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</el-menu-item>
</el-menu>
</div>
</div>
<div class="right">
<info v-if="active == 1"></info>
<download v-else></download>
</div>
</div>
</div>
</template>
<script>
import { mapState,mapActions } from 'vuex'
import info from './info'
import download from './download'
export default {
data() {
return {
typeList: [
{
index: '1',
title: '用户信息'
},{
index: '2',
title: '我的下载',
},
],
active: '1',
};
},
components: { info,download },
computed: {
...mapState('user', [
'userId','avatar','userName'
]),
},
mounted() {
},
methods: {
//
changeAvatar(res) {
this.setAvatar(res.data.filesResult.fileUrl)
},
uploadHeadImg: function() {
this.$el.querySelector('.hiddenInput').click();
},
handleSelect(key, keyPath){
console.log(key, keyPath)
this.active = key
},
}
};
</script>
<style lang="scss" scoped>
/deep/.wrap{
display: flex;
.left{
margin-right: 20px;
.inner{
width: 200px;
padding: 30px 0;
border-radius: 8px;
background-color: #fff;
}
.avatar{
width: 80px;
height: 80px;
border-radius: 50%;
}
.menu{
.el-menu-item.is-active{
color: #fff;
background-color: $main-color;
}
}
}
.right{
flex: 1;
}
}
</style>

@ -0,0 +1,551 @@
<template>
<div>
<div class="block">
<h6 class="title">用户信息</h6>
<ul class="list">
<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-date-picker
v-model="personalInformation.dateBirth"
:clearable="false"
class="block-right"
type="date">
</el-date-picker>
</div>
</li>
<li>
<label>所在国家</label>
<div class="mul">
<div class="child">
<span>国家</span>
<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>
</div>
<div class="child">
<span>省份</span>
<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>
</div>
<div class="child">
<span>城市</span>
<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>
</div>
</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>
</div>
<div class="block">
<div class="flex j-between a-center m-b-20">
<h6 class="title" style="margin-bottom: 0;">个人档案</h6>
<el-button type="text" icon="el-icon-plus" @click="addArch">新增</el-button>
</div>
<div class="information">
<div class="archives" v-for="(archive,index) in archivesList" :key="index" v-show="index == 0 || showArch">
<ul class="list">
<li>
<label>职业</label>
<div>
<el-select v-model="archive.personalCareerId" placeholder="选择职业">
<el-option v-for="item in occupationList" :key="item.value" :label="item.label" :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="archive.schoolId" filterable placeholder="选择学校" @change="id => getSchoolName(id,index)">
<el-option v-for="item in schoolList" :key="item.value" :label="item.schoolName" :value="item.schoolId"></el-option>
</el-select>
</div>
</li>
<li>
<label>专业</label>
<div class="mul">
<div class="child">
<span>专业学科</span>
<div>
<el-select v-model="archive.disciplineId" placeholder="选择专业学科" @change="id => getItemProfessionalClass(id,index)" @clear="() => clearItemClass(index)">
<el-option v-for="item in subjectList" :key="item.value" :label="item.disciplineName" :value="item.disciplineId"></el-option>
</el-select>
</div>
</div>
<div class="child">
<span>专业类</span>
<div>
<el-select v-model="archive.professionalClassId" placeholder="选择专业类" :disabled="archive.disciplineId ? false : true" @change="id => getItemProfessional(id,index)" @clear="() => clearItemProfess(index)">
<el-option v-for="item in archive.ProfessionalClassList" :key="item.professionalClassId" :label="item.professionalClassName" :value="item.professionalClassId"></el-option>
</el-select>
</div>
</div>
<div class="child">
<span>专业</span>
<div>
<el-select v-model="archive.professionalId" placeholder="选择专业" :disabled="archive.professionalClassId ? false : true" @change="getItemStuGrade">
<el-option v-for="item in archive.ProfessionalList" :key="item.professionalId" :label="item.professionalName" :value="item.professionalId"></el-option>
</el-select>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="block">
<h6 class="title">账号信息</h6>
<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 class="text-right">
<el-button type="primary" size="small" v-throttle @click="save">更新</el-button>
</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 { mapState,mapActions } from 'vuex'
import util from '@/libs/util'
export default {
data() {
return {
personalInformation: {
name:'',
workNumber:'',
password:"",
phone:'',
email:'',
provinceName:'',
cityName:'',
schoolName:'',
professionalName:'',
},
emailVisible: false,
passwordVisible: false,
phoneVisible: false,
showArch: false,
passwordForm: {
password: '',
newPassword: '',
reNewPassword: ''
},
sexList: [
{
name: '男',
value: 1
},
{
name: '女',
value: 2
}
],
countryList: [
{
label: '中国'
}
],
form: {},
provinceList:[],
cityList: [],
educationDegreeList: [
{
name: '专科',
value: 1
},
{
name: '本科',
value: 2
},
{
name: '硕士',
value: 3
},
{
name: '博士',
value: 4
},
{
name: '其他',
value: 5
}
],
schoolList: [],
curPassword: '',
accountRepeat: false,
archivesList: [],
archivesForm: {
//
personalCareerId: '', //
schoolId: '', //
schoolName: '', //
professionalClassId: '', //
professionalClassName: '', //
disciplineId: '', //
disciplineName: '', //
professionalId: '', //
professionalName: '', //
userId: this.userId
},
email: '',
emailBtnText: '发送验证码',
emailCode: '',
emailDisabled: false,
emailTimer: null,
phone: '',
phoneBtnText: '发送验证码',
phoneCode: '',
phoneDisabled: false,
phoneTimer: null
};
},
computed: {
...mapState('user', [
'userId','avatar','userName'
]),
},
mounted() {
this.getdata();
this.getProvince()
this.getSchoolData()
},
methods: {
...mapActions('user', [
'setAvatar','setUserName'
]),
tabChange(index){
this.active = index
},
getProvince(){
this.$get(this.api.queryProvince).then(res => {
this.provinceList = res.data.list
}).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
util.warningMsg('该账号已存在')
}else{
this.accountRepeat = false
}
}).catch(res => {});
},
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);
});
},
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 util.warningMsg('请输入正确的证件号码')
if(this.accountRepeat) return util.warningMsg('该账号已存在')
if(this.personalInformation.phone && !/^1[3456789]\d{9}$/.test(this.personalInformation.phone)) return util.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 util.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.setUserName(personalInformation.userName)
util.successMsg('提交成功')
this.$router.back()
}else{
util.errorMsg('提交失败')
}
}).catch(res => {})
},
concatArch(isLoadData) {
this.archivesList = this.archivesList.concat({
isNew: true,
personalCareerId: '', //
schoolId: '', //
schoolName: '', //
subjectList: this.subjectList, //
disciplineId: '', //
disciplineName: '', //
ProfessionalClassList: [], //
professionalClassId: '', //
professionalClassName: '', //
ProfessionalList: [], //
professionalId: '', //
professionalName: '', //
userId: this.userId,
personalFileId: ''
})
if(!isLoadData){
this.$nextTick(() => {
document.body.scrollTop = document.querySelector('.content-box').scrollHeight
document.documentElement.scrollTop = document.querySelector('.content-box').scrollHeight
})
}
},
addArch() {
let isEmpty = false
this.archivesList.forEach((n,k) => {
if(!n.personalCareerId) isEmpty = true
})
if(isEmpty) return this.$message.warning('请选择职业')
this.showArch = true
this.concatArch()
},
bindEmail() {
this.email = this.personalInformation.email
this.emailVisible = true
},
bindPhone() {
this.phone = this.personalInformation.phone
this.phoneVisible = true
},
bindPassword() {
this.passwordVisible = true
},
editPassword() {
if(!this.passwordForm.password) return this.$message.warning('请输入原密码')
if(!this.passwordForm.newPassword) return this.$message.warning('请输入新密码')
if(!this.passwordForm.reNewPassword) return this.$message.warning('请确认新密码')
if(this.passwordForm.newPassword.length < 6 || this.passwordForm.reNewPassword.length < 6) return this.$message.warning('请输入6位数以上的密码')
if(this.passwordForm.newPassword !== this.passwordForm.reNewPassword) return this.$message.warning('输入的新密码不一致,请重新确认')
if(this.passwordForm.password === this.passwordForm.newPassword) return this.$message.warning('原密码跟新密码不能一致')
let data = this.passwordForm
data.userid = this.userId
this.$post(this.api.examinePassword,data)
.then(res => {
if(res.errmessage == 'success'){
this.$message.success('更换成功')
this.passwordVisible = false
}
})
.catch(err => {
console.log(err);
});
},
closePassword() {
this.passwordForm = {
password: '',
newPassword: '',
reNewPassword: ''
}
},
foldArch() {
this.showArch = !this.showArch
this.$nextTick(() => {
document.body.scrollTop = document.querySelector('.content-box').scrollHeight
document.documentElement.scrollTop = document.querySelector('.content-box').scrollHeight
})
},
}
};
</script>
<style lang="scss" scoped>
.block{
padding: 34px;
margin-bottom: 20px;
background-color: #fff;
border-radius: 8px;
.title{
padding-left: 11px;
margin-bottom: 20px;
font-size: 17px;
color: $main-color;
line-height: 1.8;
border-left: 6px solid;
}
.list{
li{
display: flex;
flex-direction: column;
margin-bottom: 30px;
&>label{
margin-bottom: 5px;
font-size: 16px;
color: #4c4c4c;
}
.el-input{
width: 300px;
.el-input__inner{
border-color: #999;
}
}
.mul{
display: inline-flex;
margin-top: 10px;
.child{
display: inline-flex;
flex-direction: column;
margin-right: 20px;
&>span{
margin-bottom: 5px;
font-size: 14px;
color: #575757;
}
}
}
}
}
}
</style>

@ -0,0 +1,250 @@
<template>
<div class="wrap">
<div class="left">
<div class="inner">
<div class="date">
<span class="name">使用期限</span>
<div class="val">
2021-05-01<br><br>2021-10-01
</div>
</div>
<p class="surplus"><span class="name">剩余期限</span><span class="num">300</span> </p>
</div>
</div>
<div class="right">
<div class="block">
<h6 class="title">平台数据统计</h6>
<ul class="stat">
<li>
<p class="people">
<span class="num">4</span>
</p>
<p class="text">本校累计用户数量</p>
</li>
<li>
<p class="people">
<span class="num">2</span>
</p>
<p class="text">平均日访客量</p>
</li>
<li>
<p class="people">
<span class="num">4</span>
</p>
<p class="text">累计下载</p>
</li>
<li>
<p class="people">
<span class="num">4</span>
</p>
<p class="text">当前在线人数</p>
</li>
</ul>
</div>
<div class="block">
<div class="flex m-b-20">
<ul class="filter">
<li>
<label>查询时间区域</label>
<el-date-picker v-model="date" align="right" unlink-panels type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" format="yyyy-MM-dd" value-format="yyyy-MM-dd" clearable size="small"></el-date-picker>
</li>
</ul>
</div>
<div class="flex j-between">
<h6 class="title">按数据库统计使用概况</h6>
<div>
<el-button type="primary" size="small" v-auth="'/system/list:员工管理:批量导入'">导出数据</el-button>
</div>
</div>
<el-table :data="listData" class="table" stripe header-align="center" row-key="id" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="80" align="center"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column prop="practiseName" label="数据分类" align="center"></el-table-column>
<el-table-column prop="paperName" label="数据库类别" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="下载量" align="center"></el-table-column>
<el-table-column prop="peopleNum" label="点击量" align="center"></el-table-column>
</el-table>
</div>
<div class="block">
<div class="flex j-between">
<h6 class="title">按月份统计数据库使用概况</h6>
<div>
<el-button type="primary" size="small" v-auth="'/system/list:员工管理:批量导入'">导出数据</el-button>
</div>
</div>
<el-table :data="monthData" class="table" stripe header-align="center" row-key="id" :span-method="objectSpanMethod" @selection-change="handleSelectionChange1">
<el-table-column type="selection" width="80" align="center"></el-table-column>
<el-table-column prop="year" label="年份" align="center"></el-table-column>
<el-table-column prop="type" label="类别" align="center"></el-table-column>
<el-table-column prop="month1" label="1月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="2月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="3月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="4月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="5月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="6月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="7月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="8月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="9月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="10月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="11月" align="center"></el-table-column>
<el-table-column prop="questionsNum" label="12月" align="center"></el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
date: [],
startTime: '',
endTime: '',
listData: [],
multipleSelection: [],
monthData: [
{
year: 2020,
type: '登录量',
month1: 1
},{
year: 2020,
type: '下载量',
month1: 1
},{
year: 2020,
type: '点击量',
month1: 1
},
],
multipleSelection1: [],
}
},
watch: {
date: function(val){
if(val){
this.startTime = val[0]
this.endTime = val[1]
}else{
this.startTime = ''
this.endTime = ''
}
this.getData()
}
},
mounted() {
},
methods: {
getData(){
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 3,
colspan: 1
};
}
}
},
handleSelectionChange(val) {
this.multipleSelection = val
},
handleSelectionChange1(val) {
this.multipleSelection1 = val
},
}
};
</script>
<style lang="scss" scoped>
.wrap{
display: flex;
.left{
margin-right: 20px;
.inner{
width: 200px;
padding: 15px;
background-color: #fff;
border-radius: 8px;
.date{
display: flex;
align-items: center;
.val{
text-align: center;
line-height: 1.8;
font-size: 15px;
color: $main-color;
}
}
.surplus{
margin-top: 15px;
.num{
font-size: 24px;
color: $main-color;
font-weight: bold;
}
}
.name{
font-size: 14px;
color: #404040;
}
}
}
.block{
padding: 34px;
margin-bottom: 20px;
background-color: #fff;
border-radius: 8px;
.title{
padding-left: 11px;
margin-bottom: 20px;
font-size: 17px;
color: $main-color;
line-height: 1.8;
border-left: 6px solid;
}
.stat{
display: flex;
li{
flex: 1;
height: 120px;
padding: 28px 0 18px;
margin-right: 27px;
text-align: center;
background: url(../../../assets/img/stat1.png) 0 0/100% 100% no-repeat;
&:nth-child(2){
background-image: url(../../../assets/img/stat2.png);
}
&:nth-child(3){
background-image: url(../../../assets/img/stat3.png);
}
&:last-child{
margin-right: 0;
background-image: url(../../../assets/img/stat4.png);
}
.people{
color: #fff;
font-size: 24px;
.num{
font-size: 41px;
}
}
.text{
color: #fff;
font-size: 15px;
}
}
}
}
}
</style>

@ -0,0 +1,627 @@
<template>
<div>
<div class="page">
<div class="page-content">
<div class="tool">
<ul class="filter">
<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/list:员工管理:新增员工'">新增员工</el-button>
<el-button type="primary" size="small" round @click="batchImport" v-auth="'/system/list:员工管理:批量导入'">批量导入</el-button>
<el-button type="primary" size="small" round @click="delAllSelection" v-auth="'/system/list:员工管理:批量删除'">批量删除</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="account" label="账号" align="center"></el-table-column>
<el-table-column prop="userName" label="姓名" align="center"></el-table-column>
<el-table-column prop="workNumber" label="工号/学号" align="center"></el-table-column>
<el-table-column prop="roleName" label="账号角色" align="center"></el-table-column>
<el-table-column prop="loginNumber" label="登录次数" align="center">
<template slot-scope="scope">
{{scope.row.loginNumber ? scope.row.loginNumber : 0}}
</template>
</el-table-column>
<el-table-column prop="lastLoginTime" label="上次登录时间" width="160" align="center"></el-table-column>
<el-table-column label="操作" align="center" width="200">
<template slot-scope="scope">
<el-button type="text" @click="showTeacher(scope.row)" v-auth="'/system/list:员工管理:查看'">查看</el-button>
<el-button type="text" @click="editTeacher(scope.row)" v-auth="'/system/list:员工管理:编辑'">编辑</el-button>
<el-button type="text" @click="resetPassword(scope.row)" v-auth="'/system/list:员工管理:重置密码'">重置密码</el-button>
<el-button type="text" @click="delTeacher(scope.row)" v-auth="'/system/list:员工管理:删除'">删除</el-button>
<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)"></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total,prev, pager, next" :current-page="page" @current-change="handleCurrentChange" :total="total"></el-pagination>
</div>
<el-dialog :title="isDetail ? '查看员工' : (isAddteacher ? '新增员工' : '编辑员工')" :visible.sync="teacherVisible" width="500px" @close="closeTeacher" class="dialog" :close-on-click-modal="false">
<el-form ref="teacherForm" :model="teacherForm" :rules="rules" label-width="110px" label-suffix="" :disabled="isDetail">
<el-form-item prop="userAccount" label="账号">
<el-input v-model="teacherForm.userAccount" ref="account" placeholder="请输入职工账号" @change="accountChange"></el-input>
</el-form-item>
<el-form-item prop="userName" label="用户姓名">
<el-input v-model="teacherForm.userName" placeholder="请输入员工姓名"></el-input>
</el-form-item>
<el-form-item prop="roleValue" label="账号角色">
<el-select v-model="teacherForm.roleValue" placeholder="请选择账号角色" :disabled="!isAddteacher">
<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="teacherForm.uniqueIdentificationAccount" placeholder="请输入工号/学号获取唯一标识"></el-input>
</el-form-item>
<el-form-item prop="phone" label="手机号">
<el-input v-model="teacherForm.phone" placeholder="请输入手机号" maxlength="11"></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model="teacherForm.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="workNumber" label="工号/学号">
<el-input v-model="teacherForm.workNumber" placeholder="请输入职工工号" @change="workNumberChange"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer" v-if="!isDetail">
<el-button size="small" @click="teacherVisible = false"> </el-button>
<el-button size="small" type="primary" @click="saveSure('teacherForm')"> </el-button>
</span>
</el-dialog>
<el-dialog title="批量导入" :visible.sync="importVisible" width="400px" @close="closeImport" :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.clientId}" 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>
</div>
</div>
</template>
<script>
import Setting from '@/setting';
import { mapState } from 'vuex';
import util from '@/libs/util'
export default {
data() {
return {
pages: 10,
isDetail: false,
props: { multiple: true },
orgList: [],
isAddteacher: false,
teacherVisible: false,
staffShowVisible: false,
roleList: [],
teacherForm: {
teacherId: '',
userName: '',
roleValue: '',
phone: '',
uniqueIdentificationAccount: '',
workNumber: '',
email: '',
major: '',
department: '',
userAccount: '',
major: '',
clientId: this.clientId,
clientName: this.clientName,
},
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'
}
],
department: [
{ required: true, message: '请选择二级部门', trigger: 'change' }
],
phone: [
// { required: true, message: '', trigger: 'blur' },
{
pattern: /^1[3456789]\d{9}$/,
message: '请输入正确的手机号',
trigger: 'blur'
}
],
email: [
// { required: true, message: '', trigger: 'blur' },
{
pattern: /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/,
message: '请输入正确的邮箱',
trigger: 'blur'
}
],
// schoolId: [
// { required: true, message: '', trigger: 'change' }
// ],
},
listData: [],
importVisible: false,
keyword: '',
page: 1,
pageSize: 10,
total: 0,
departmentList: [],
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
};
},
computed: {
...mapState('user', [
'clientId','clientName'
]),
...mapState('layout', [
'isIE'
])
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.initData()
},500)
}
},
mounted(){
this.getOrg()
this.teacherForm.clientId = this.clientId
this.teacherForm.clientName = this.clientName
this.getData()
this.getRoles()
},
methods: {
getOrg(){
let data = {
schoolId: this.clientId
}
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 totalPage = Math.ceil((this.total - 1) / this.pageSize)
let currentPage = this.page > totalPage ? totalPage : this.page
this.page = currentPage < 1 ? 1 : currentPage
let data = {
staffProfessionalArchitectureIds: this.oneDepartmentIds,
staffGradeIds: this.twoDepartmentIds,
searchContent: this.keyword,
schoolId: this.clientId,
pageNum: this.page,
pageSize: this.pageSize
}
this.$get(`${this.api.queryStaff}/${this.page}/${this.pageSize}`,data).then(res => {
this.listData = res.data.staffList.list
this.total = res.data.staffList.totalCount
if(!this.listData.length && this.total){
this.page--
this.getData()
}
}).catch(res => {})
},
initData(){
this.page = 1
this.getData()
},
orgChange(node){
this.twoDepartmentIds = node.map(n => n[1]).toString()
this.initData()
},
getRoles(){
let data = {
clientId: this.clientId
}
this.$get(`${this.api.queryRoles}/1/100`,data).then(res => {
this.roleList = res.data.items
}).catch(res => {})
},
resetPassword(row){
this.$confirm(`重置后的密码为:${Setting.initialPassword},确定重置?`, '提示', {
type: 'info',
customClass: 'normal'
}).then(() => {
let data = {
userId: row.userId,
password: Setting.initialPassword
}
this.$post(this.api.userinfoUpdate,data).then(res => {
if(res.success){
util.successMsg('重置成功')
}else{
util.errorMsg('重置失败')
}
}).catch(res => {})
}).catch(() => {})
},
accountChange(){
if(this.teacherForm.userAccount !== this.originalAccount){
this.$get(`${this.api.getAccount}?account=${this.teacherForm.userAccount}`).then(res => {
if(res.data.userInfo){
this.accountRepeat = true
util.warningMsg('该账号已存在')
}else{
this.accountRepeat = false
}
}).catch(res => {})
}else{
this.accountRepeat = false
}
},
workNumberChange(){
if(this.teacherForm.workNumber !== this.originalWorkNumber){
this.$get(`${this.api.getWorkNumber}?workNumber=${this.teacherForm.workNumber}`).then(res => {
if(res.data.staff){
this.workNumberRepeat = true
util.warningMsg('该工号已存在')
}else{
this.workNumberRepeat = false
}
}).catch(res => {})
}else{
this.workNumberRepeat = false
}
},
closeTeacher(){
this.$refs.teacherForm.resetFields()
this.teacherForm.clientId = this.clientId
this.teacherForm.clientName = this.clientName
this.teacherForm.department = ''
this.teacherForm.major = ''
this.teacherForm.workNumber = ''
this.teacherForm.userId = ''
this.teacherForm.staffId = ''
},
addTeacher(){
this.isDetail = false
this.teacherVisible = true
this.isAddteacher = true
this.teacherForm.teacherId = ''
},
getStaffDetail(userId){
this.$get(`${this.api.getStaff}/${userId}`).then(res => {
let user = res.data.userInfo;
let or = res.data.staff;
this.teacherForm.uniqueIdentificationAccount = user.uniqueIdentificationAccount
this.teacherForm.clientId = user.clientId
this.teacherForm.clientName = user.clientName
this.teacherForm.userName = user.userName
this.teacherForm.phone = user.phone
this.teacherForm.email = user.email
this.teacherForm.userAccount = user.account
this.originalAccount = user.account
this.teacherForm.userId = user.userId
this.teacherForm.schoolId = user.schoolId
this.teacherForm.roleValue = user.roleId
this.teacherForm.major = or.staffProfessionalArchitectureId
this.teacherForm.department = or.staffGradeId
this.teacherForm.workNumber = or.workNumber
this.originalWorkNumber = or.workNumber
this.isManager = true
this.teacherForm.staffId = or.staffId
this.getDepartment()
}).catch(res => {});
},
editTeacher(row){
this.isDetail = false
this.teacherVisible = true
this.isAddteacher = false
this.AccountNoAdd = false
this.teacherForm.teacherId = row.staffId
this.getStaffDetail(row.staffId)
},
showTeacher(row){
this.staffShowVisible = true
this.isDetail = true
this.isAddManage = false
this.AccountNoAdd = false
this.teacherForm.manageId = row.staffId
this.getStaffDetail(row.staffId)
},
getDepartment(){
let data = {
staffProfessionalArchitectureId: this.teacherForm.major
}
this.$get(this.api.queryStaffGrade,data).then(res => {
this.departmentList = res.data.staffGradeList
}).catch(res => {});
},
async saveSure(teacherForm){
this.$refs[teacherForm].validate((valid) => {
if (valid) {
if(this.accountRepeat) return util.warningMsg('该账号已存在')
if(this.workNumberRepeat) return util.warningMsg('该工号已存在')
let isTeacher = false
let isManager = false
let data = {
userInfo: {
userId: this.teacherForm.userId,
userName: this.teacherForm.userName,
account: this.teacherForm.userAccount,
clientId: this.teacherForm.clientId,
clientName: this.teacherForm.clientName,
roleId: this.teacherForm.roleValue,
phone: this.teacherForm.phone,
email: this.teacherForm.email,
isPort: 2,
uniqueIdentificationAccount: this.teacherForm.uniqueIdentificationAccount ? this.teacherForm.uniqueIdentificationAccount : Date.parse(new Date()),
}
}
let oneDepartmentName = '';
for(let i in this.orgList){
if(this.orgList[i].staffProfessionalArchitectureId == this.teacherForm.major) {
oneDepartmentName = this.orgList[i].staffProfessionalArchitectureName
break;
}
}
let twoDepartmentName = this.departmentList.find((n) => {
return n.staffGradeId == this.teacherForm.department
}).staffGradeName;
data.staff = {
roleId: this.teacherForm.roleValue,
isPort: 2,
schoolId: this.teacherForm.clientId,
staffId: this.teacherForm.staffId,
userId: this.teacherForm.userId,
workNumber: this.teacherForm.workNumber,
staffProfessionalArchitectureId: this.teacherForm.major,
staffGradeId: this.teacherForm.department,
staffProfessionalArchitectureName: oneDepartmentName,
staffGradeName: twoDepartmentName,
};
if(this.teacherForm.teacherId){
this.$post(this.api.updateStaff,data).then(res => {
this.teacherVisible = false
util.successMsg('编辑成功');
this.getData()
}).catch(res => {});
}else{
this.$post(this.api.addStaff,data).then(res => {
this.teacherVisible = false
util.successMsg('添加成功');
this.getData()
}).catch(res => {});
}
}else{
return false;
}
})
},
delTeacher(row){
this.$confirm('此删除操作不可逆,是否确认删除选中项?', '提示', {
type: 'warning'
})
.then(() => {
let data = {
staffIds: row.staffId
}
this.$del(this.api.deleteStaffs,data).then(res => {
util.successMsg('删除成功')
this.getData()
}).catch(res => {});
})
.catch(() => {});
},
switchOff(val,row,index) {
let data = {
id: row.id,
isDisable: val
}
this.$post(this.api.updateClient,data).then((res) => {
val == 1 ? util.warningMsg('该院校系统使用权限已关闭') : util.successMsg('该院校系统使用权限已激活')
}).catch((res) => {
})
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
delAllSelection() {
if(this.multipleSelection.length != ''){
let newArr = this.multipleSelection
let delList = newArr.map(item => {
return item.staffId
})
//
this.$confirm(`此批量删除操作不可逆,是否确认删除${util.ellipsisStr(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()
util.successMsg('删除成功')
this.getData()
}).catch(res => {});
}).catch(() => {});
}else{
util.errorMsg('请先选择数据 !')
}
},
batchImport(){
this.importVisible = true
this.uploadList = []
this.uploadFaild = false
},
searchTeacher(){
this.page = 1
this.getData()
},
handleCurrentChange(val) {
this.page = val
this.$refs.table.clearSelection()
this.getData()
},
downLoad(){
location.href = this.api.downloadStaffTemp
},
showFaild(){
location.href = `${this.api.exportFailureStaff}?token=${this.token}`
},
//
handleExceed(files, fileList) {
util.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{
util.successMsg('上传成功')
}
}else{
res.data.message ? util.errorMsg(res.data.message) : util.errorMsg('上传失败,请检查数据')
}
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
this.uploadList = fileList
this.uploadFaild = false
},
closeImport(){
this.uploadList = []
},
uploadSure(){
this.importVisible = false
this.page = 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>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,25 @@
/**
* @description 鉴权指令
* 当传入的权限当前用户没有时会移除该组件
* 用例<Tag v-auth">text</Tag> 或者:<Tag v-auth="'user:编辑'">text</Tag>
* */
import store from '@/store';
export default {
inserted (el, binding, vnode) {
let btnText = ''
if(binding.value){
btnText = binding.value
}else{
btnText = `${vnode.context.$route.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,12 @@
/**
* @description 返回缺省值
* 传入的如果是null就返回'--'
* 用例<Tag :default="val">text</Tag> <Tag>{{val | default}}</Tag>
* */
const defaultShow = (val) => {
return val == null ? '--' : val
}
module.exports = {
defaultShow
}

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

@ -0,0 +1,161 @@
import axios from 'axios'
import util from '@/libs/util'
import router from '@/router/index'
import Setting from '@/setting'
const service = axios.create({
baseURL: Setting.apiBaseURL,
timeout: 50000
})
// post请求头
service.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
// 请求拦截器
// service.interceptors.request.use(config => {
// if (sessionStorage.getItem('token')) {
// // 存在将token写入 request header
// config.headers.Authorization = `${sessionStorage.getItem('token')}`;
// }
// return config;
// }, err => {
// util.errorMsg({
// message: '退出登陆',
// onClose: function () {
// router.push({name: 'login'});
// }
// })
// return Promise.reject(err);
// })
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data
if (res.success) {
return Promise.resolve(res).catch(e => {})
} else {
switch (res.code) {
case 201:
util.errorMsg(res.message ? res.message : '数据请求异常')
break;
default:
Promise.reject(res).catch(e => {})
}
return Promise.reject(res).catch(e => {})
}
},
// 服务器状态码不是200的情况
error => {
if (error.res.status) {
switch (error.res.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
// 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:
Promise.reject(res)
}
return Promise.reject(error.res);
}
}
);
function get(url, params){
return new Promise((resolve, reject) =>{
service.get(url, {params: params})
.then(res => {
if(res){
resolve(res)
}else{
reject()
}
}).catch(err => {
reject(err.data)
})
})
}
function post(url, params){
return new Promise((resolve, reject) =>{
service.post(url,params)
.then(res => {
if(res){
resolve(res)
}else{
reject()
}
}).catch(err => {
reject(err.data)
})
})
}
function del(url, params){
return new Promise((resolve, reject) =>{
service.delete(url, {
params
})
.then(res => {
if(res){
resolve(res)
}else{
reject()
}
}).catch(err => {
reject(err.data)
})
})
}
function put(url, params){
return new Promise((resolve, reject) =>{
service.put(url, {
params
})
.then(res => {
if(res){
resolve(res)
}else{
reject()
}
}).catch(err => {
reject(err.data)
})
})
}
export { get,post,del,put }

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

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

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

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

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

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

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

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

@ -0,0 +1,28 @@
import BasicLayout from '@/layouts/home';
const meta = {};
const pre = 'wrongBook-';
export default {
path: '/wrongBook',
name: 'wrongBook',
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import('@/pages/wrongBook/list'),
meta: { title: '我的错题本' }
},{
name: `${pre}do`,
path: `do`,
component: () => import('@/pages/wrongBook/do'),
meta: { title: '错题练习' }
},
]
};

@ -0,0 +1,15 @@
import router from './index'
import Setting from '@/setting'
import util from '@/libs/util'
router.beforeEach((to, from, next) => {
document.title = Setting.titleSuffix;
const role = util.session.get(Setting.usernameKey);
if (!role && to.path !== '/login') {
next('/login')
} else if(role && to.path == '/login') {
next('/index')
} else {
next()
}
});

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

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

@ -0,0 +1,68 @@
/**
* 业务配置
* */
const env = process.env.NODE_ENV;
const Setting = {
/**
* 基础配置
* */
// 网页标题的后缀
titleSuffix: '或然数据平台',
// 路由模式,可选值为 history 或 hash
routerMode: 'hash',
// 页面切换时,是否显示模拟的进度条
showProgressBar: true,
// 接口请求地址
// apiBaseURL: env === 'development' ? 'http://192.168.31.151:8001' : 'http://39.108.250.202:8000',
apiBaseURL: env === 'development' ? 'http://39.108.250.202:9000' : 'http://39.108.250.202:9000',
// 接口请求返回错误时,弹窗的持续时间,单位:秒
modalDuration: 3,
// 接口请求返回错误时,弹窗的类型,可选值为 Message 或 Notice
errorModalType: 'Message',
// Cookies 默认保存时间,单位:天
cookiesExpires: 1,
/**
* sessionStorage里state的key
*/
storeKey: 'data_store',
/**
* sessionStorage里username的key
*/
usernameKey: 'data_username',
/**
* 默认密码
*/
initialPassword: '111aaa',
/**
* 多语言配置
* */
i18n: {
// 默认语言
default: 'zh',
// 是否根据用户电脑配置自动设置语言(仅第一次有效)
auto: false
},
/**
* 布局配置
* */
layout: {
// 需要隐藏顶栏的页面路径
hideNavList: ['practice-do','practice-randomDo','setting-person','achievement-assessment','achievement-practice','exam-do','exam-detail','wrongBook-do'],
},
/**
* 功能配置
* */
// 相同路由,不同参数间进行切换,是否强力更新
sameRouteForceUpdate: false,
// 是否使用动态路由
dynamicRoute: false,
// 文件上传
upload: {
apiURL: 'http://8.134.8.197:8001',
maxSize: 30,
},
};
export default Setting;

@ -0,0 +1,10 @@
const getters = {
userId: state => state.user.info.userId,
roleId: state => state.user.info.roleId,
userName: state => state.user.info.userName,
account: state => state.user.info.account,
phone: state => state.user.info.phone,
clientId: state => state.user.info.clientId,
clientName: state => state.user.info.clientName,
}
export default getters

@ -0,0 +1,25 @@
import Vue from 'vue';
import Vuex from 'vuex';
import getters from './getters'
Vue.use(Vuex);
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
modules,
getters
})
export default store

@ -0,0 +1,32 @@
/**
* 成绩管理
* */
export default {
namespaced: true,
state: {
id: '',
assessmentId: '',
assessmentName: '',
classId: '',
score: 0,
timeSpent: 0
},
getters: {
},
mutations: {
SET_INFO: (state, info) => {
state.id = info.id
state.assessmentId = info.assessmentId
state.assessmentName = info.assessmentName
state.classId = info.classId
state.score = info.score
state.timeSpent = info.timeSpent
},
},
actions: {
setInfo({ commit },info) {
commit('SET_INFO',info)
},
}
}

@ -0,0 +1,19 @@
/**
* 客户管理
* */
export default {
namespaced: true,
state: {
provinceList: []
},
mutations: {
SET_PROVINCE: (state, provinceList) => {
state.provinceList = provinceList
},
},
actions: {
setProvince({ commit, state, dispatch },provinceList) {
commit('SET_PROVINCE',provinceList)
},
}
}

@ -0,0 +1,24 @@
/**
* 通用
* */
const roleList = {
'1': '超级管理员',
'2': '管理员',
'3': '老师',
'4': '学生'
}
export default {
namespaced: true,
state: {
},
mutations: {
},
actions: {
getRole (id) {
return roleList[id] || '未知状态'
}
}
}

@ -0,0 +1,97 @@
/**
* 试卷管理
* */
export default {
namespaced: true,
state: {
typeList: [
{
id: 1,
name: '期中考试'
},{
id: 2,
name: '期末考试'
},{
id: 3,
name: '模拟考'
}
],
stateList: [
{
id: 0,
name: '待开始'
},{
id: 1,
name: '进行中'
},{
id: 2,
name: '已提交'
}
],
assessmentStateList: [
{
id: 1,
name: '待开始'
},{
id: 2,
name: '进行中'
},{
id: 3,
name: '已结束'
}
],
degreeList: [
{
id: 0,
label: '简单'
},{
id: 1,
label: '一般'
},{
id: 2,
label: '较难'
},{
id: 3,
label: '很难'
},
],
assessmentName: '',
testPaperId: '',
assessmentId: '',
teacherId: '',
classId: '',
paperName: '',
countdown: '',
assessmentName: ''
},
getters: {
getDegreeName: state => id => {
return id != null ? state.degreeList.find(n => n.id == id).label : ''
},
getTypeName: state => id => {
return id != null ? state.typeList.find(n => n.id == id).name : ''
},
getStateName: state => id => {
return id != null ? state.stateList.find(n => n.id == id).name : ''
},
getAssessmentStateName: state => id => {
return id != null ? state.assessmentStateList.find(n => n.id == id).name : ''
},
},
mutations: {
SET_INFO: (state, info) => {
state.assessmentName = info.assessmentName
state.assessmentId = info.assessmentId
state.teacherId = info.teacherId
state.classId = info.classId
state.testPaperId = info.testPaperId
state.countdown = info.countdown
state.assessmentName = info.assessmentName
},
},
actions: {
setInfo({ commit },info) {
commit('SET_INFO',info)
},
}
}

@ -0,0 +1,24 @@
/**
* 布局管理
* */
// 是否IE
function isIE() {
if (!!window.ActiveXObject || "ActiveXObject" in window) return true
return false
}
export default {
namespaced: true,
state: {
isIE: isIE()
},
mutations: {
SET_IE: (state, val) => {
state.isIE = val
},
},
actions: {
}
}

@ -0,0 +1,47 @@
/**
* 试卷管理
* */
export default {
namespaced: true,
state: {
degreeList: [
{
id: 0,
label: '简单'
},{
id: 1,
label: '一般'
},{
id: 2,
label: '较难'
},{
id: 3,
label: '很难'
},
],
practiseId: '',
paperId: '',
practiseName: '',
isContinue: '',
identification: '',
},
getters: {
getDegreeName: state => id => {
return id != null ? state.degreeList.find(n => n.id == id).label : ''
}
},
mutations: {
SET_INFO: (state, info) => {
state.practiseId = info.practiseId
state.paperId = info.paperId
state.practiseName = info.practiseName
state.isContinue = info.isContinue
state.identification = info.identification
},
},
actions: {
setInfo({ commit },info) {
commit('SET_INFO',info)
},
}
}

@ -0,0 +1,108 @@
import addRoutes from '@/libs/route/addRoutes';
import Setting from '@/setting';
import util from '@/libs/util';
import { Message } from 'element-ui';
import {post,get,del,put} from '@/plugins/requests/index.js'
import api from '@/api';
/**
* 用户信息
* */
export default {
namespaced: true,
state: {
avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
token: '',
userId: '',
roleId: '',
userName: '',
account: '',
phone: '',
clientId: '',
clientName: '',
},
mutations: {
SET_INFO: (state, info) => {
info.avatar && (state.avatar = info.avatar)
state.userId = info.userId
state.roleId = info.roleId
state.userName = info.userName
state.account = info.account
state.phone = info.phone
state.clientId = info.clientId
state.clientName = info.clientName
},
SET_TOKEN: (state, token) => {
state.token = token
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_USERNAME: (state, userName) => {
state.userName = userName
},
SET_ROLEID: (state, roleId) => {
state.roleId = roleId
},
SET_CLIENTID: (state, clientId) => {
state.clientId = clientId
},
SET_CLIENTNAME: (state, clientName) => {
state.clientName = clientName
}
},
actions: {
login({ state,commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
get(api.logins,{ account: username.trim(), password: password }).then(res => {
if(res.success){
let user = res.data.userInfo
if(user.roleId == 4){
let routes = res.data.permissions[0].children
commit('SET_INFO',{
avatar: user.userAvatars,
userId: user.userId,
roleId: user.roleId,
userName: user.userName,
account: user.account,
phone: user.phone,
clientId: user.clientId,
clientName: user.clientName,
})
Setting.dynamicRoute && addRoutes(routes)
util.session.set(Setting.usernameKey, user.userName)
util.successMsg('登录成功');
resolve()
}else{
util.errorMsg('该用户没有权限')
}
}else{
util.errorMsg(res.message)
}
}).catch(error => {
reject(error)
})
})
},
logout({ commit, state, dispatch }) {
return new Promise((resolve, reject) => {
util.session.remove(Setting.usernameKey);
util.session.remove(Setting.storeKey);
location.reload()
resolve()
})
},
setAvatar({ state,commit },avatar) {
commit('SET_AVATAR',avatar)
let data = {
userId: state.userId,
userAvatars: avatar
}
post(api.userinfoUpdate,data).then(res => {}).catch(res => {})
},
setUserName({ state,commit },userName) {
commit('SET_USERNAME',userName)
},
}
}

@ -0,0 +1,24 @@
/**
* 我的错题本
* */
export default {
namespaced: true,
state: {
qid: '',
type: 1
},
getters: {
},
mutations: {
SET_INFO: (state, info) => {
state.qid = info.qid
state.type = info.type
},
},
actions: {
setInfo({ commit },info) {
commit('SET_INFO',info)
},
}
}

@ -0,0 +1,373 @@
@import "./default/index.scss";
@font-face{
font-family: youshe;
src: url('font/YouSheBiaoTiHei.ttf');
}
[v-cloak] {
display: none;
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-thumb {
width: 5px;
border-radius: 6px;
background: rgba(86,141,242,.7);
}
.required{
font-size: 16px;
color: $--color-primary;
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: $--color-primary !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);
}
}
.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;
}
}
}
.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;
.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: $--color-primary;
}
&.active {
border-radius: 4px;
color: #fff;
background-color: $--color-primary;
}
}
}
}
}
.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: $--color-primary !important;
}
}
.el-table{
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.06);
border-bottom: 0;
.cell{
font-size: 14px;
.el-checkbox{
&:before{
content: '全选';
margin-right: 5px;
color: #fff;
font-size: 14px;
opacity: 0;
}
}
}
th{
background: $--color-primary !important;
.cell{
color: #fff;
font-size: 14px;
font-weight: normal;
.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;
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;
}
}
&:not(.normal){
.el-button--primary{
color: #606266;
background: #fff;
border-color: #DCDFE6;
&:hover{
color: $--color-primary;
border-color: #efbdbb;
background-color: #fae9e8;
}
}
}
}
.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;
}
}
.el-tooltip__popper{
width: 300px;
}
@media(max-width: 1600px){
.el-table{
.el-switch__label--right.is-active{
left: 8px;
}
}
}

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

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

@ -0,0 +1,446 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>IconFont Demo</title>
<link rel="shortcut icon" href="https://img.alicdn.com/tps/i4/TB1_oz6GVXXXXaFXpXXJDFnIXXX-64-64.ico" type="image/x-icon"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=1540265" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe63d;</span>
<div class="name">已勾选32</div>
<div class="code-name">&amp;#xe63d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe63e;</span>
<div class="name">未勾选32</div>
<div class="code-name">&amp;#xe63e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe64a;</span>
<div class="name">未勾选40</div>
<div class="code-name">&amp;#xe64a;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe64b;</span>
<div class="name">已勾选40</div>
<div class="code-name">&amp;#xe64b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe626;</span>
<div class="name">实 向右箭头-01</div>
<div class="code-name">&amp;#xe626;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe625;</span>
<div class="name">实 向下箭头-01</div>
<div class="code-name">&amp;#xe625;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe72d;</span>
<div class="name">加号-填充</div>
<div class="code-name">&amp;#xe72d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe769;</span>
<div class="name">42指向上、上箭头</div>
<div class="code-name">&amp;#xe769;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe76b;</span>
<div class="name">44指向下、下箭头</div>
<div class="code-name">&amp;#xe76b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe6e9;</span>
<div class="name">群蜂删除-充</div>
<div class="code-name">&amp;#xe6e9;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe614;</span>
<div class="name">qq</div>
<div class="code-name">&amp;#xe614;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe68a;</span>
<div class="name">微信-36</div>
<div class="code-name">&amp;#xe68a;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.eot');
src: url('iconfont.eot?#iefix') format('embedded-opentype'),
url('iconfont.woff2') format('woff2'),
url('iconfont.woff') format('woff'),
url('iconfont.ttf') format('truetype'),
url('iconfont.svg#iconfont') format('svg');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-yigouxuan"></span>
<div class="name">
已勾选32
</div>
<div class="code-name">.icon-yigouxuan
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-weigouxuan"></span>
<div class="name">
未勾选32
</div>
<div class="code-name">.icon-weigouxuan
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-weigouxuan1"></span>
<div class="name">
未勾选40
</div>
<div class="code-name">.icon-weigouxuan1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-yigouxuan1"></span>
<div class="name">
已勾选40
</div>
<div class="code-name">.icon-yigouxuan1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shixiangyoujiantou-"></span>
<div class="name">
实 向右箭头-01
</div>
<div class="code-name">.icon-shixiangyoujiantou-
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shixiangxiajiantou-"></span>
<div class="name">
实 向下箭头-01
</div>
<div class="code-name">.icon-shixiangxiajiantou-
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jiahao"></span>
<div class="name">
加号-填充
</div>
<div class="code-name">.icon-jiahao
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-up"></span>
<div class="name">
42指向上、上箭头
</div>
<div class="code-name">.icon-up
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-down"></span>
<div class="name">
44指向下、下箭头
</div>
<div class="code-name">.icon-down
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-delete"></span>
<div class="name">
群蜂删除-充
</div>
<div class="code-name">.icon-delete
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-qq"></span>
<div class="name">
qq
</div>
<div class="code-name">.icon-qq
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-weixin"></span>
<div class="name">
微信-36
</div>
<div class="code-name">.icon-weixin
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>兼容性良好,支持 IE8+,及所有现代浏览器。</li>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
<li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-yigouxuan"></use>
</svg>
<div class="name">已勾选32</div>
<div class="code-name">#icon-yigouxuan</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-weigouxuan"></use>
</svg>
<div class="name">未勾选32</div>
<div class="code-name">#icon-weigouxuan</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-weigouxuan1"></use>
</svg>
<div class="name">未勾选40</div>
<div class="code-name">#icon-weigouxuan1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-yigouxuan1"></use>
</svg>
<div class="name">已勾选40</div>
<div class="code-name">#icon-yigouxuan1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shixiangyoujiantou-"></use>
</svg>
<div class="name">实 向右箭头-01</div>
<div class="code-name">#icon-shixiangyoujiantou-</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shixiangxiajiantou-"></use>
</svg>
<div class="name">实 向下箭头-01</div>
<div class="code-name">#icon-shixiangxiajiantou-</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jiahao"></use>
</svg>
<div class="name">加号-填充</div>
<div class="code-name">#icon-jiahao</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-up"></use>
</svg>
<div class="name">42指向上、上箭头</div>
<div class="code-name">#icon-up</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-down"></use>
</svg>
<div class="name">44指向下、下箭头</div>
<div class="code-name">#icon-down</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-delete"></use>
</svg>
<div class="name">群蜂删除-充</div>
<div class="code-name">#icon-delete</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-qq"></use>
</svg>
<div class="name">qq</div>
<div class="code-name">#icon-qq</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-weixin"></use>
</svg>
<div class="name">微信-36</div>
<div class="code-name">#icon-weixin</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

@ -0,0 +1,71 @@
@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1589437921018'); /* IE9 */
src: url('iconfont.eot?t=1589437921018#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAdgAAsAAAAADwwAAAcTAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCESgqOeIt2ATYCJAM0CxwABCAFhG0HgTMbpQxRlHBSFNlX2JThXqSJ4cz0aLyxzNkVgYOP2N97wQhUeQbPDZA1QByDeHha+9+5M7PrD1FpdI8mCSqJLulDJPFDxCQTvUQS6Qtka3ukU0/kuK8wfBBwMr1kmeTIb8hUohVh6lTeCHDCrRPPf5v6f+sQfS+QqgmpiZLNw+ZI6zMXZGL3nXY47elJFnjALaE4zjzyjJN773yuzM/7H4oZ9NV+v/q1g1ddvP1QmE5JlPRM7uAv5klMk0vWTBWTLpoJEUIja6hWSkNhOklN/ds4n0BvhyLMuZ6hKdArLC1Q4a4iG0Gfi1JaHEMbXtfsW8S8SpsepzuAJ+HLx28hoSepMmvby3e6LdC2EN2eV0ykW36MR/MlQFiJjGNAEej7WvtLgB6aM6evXtwH1glnTloW1snRYnBhky+LxyuL9glaGNmaDbRsJYR1tl+seImrgUGtEtLc//GMeo1WR9QYfUSrp7nohWgXDRrJBqpBcoAqkGagAGkBSiADQBlkEKiAbAI/N/mCYHoWi1HDEgWoBbGjlg7M/OpbgEMgnUf0fxab8kjK0tvq8cZ6/dpKwk4bNsXFx4bHR4RHcty4LVnR4xp/2TFxDN42tgefhUpEMeeqppXCU50JyT/gkVCD+EiEgl56LOkMN+6cAfyKs3dvomHU7fvnq96Uc/duIXMMqWmhNRoax1m8jNWfPorp2jlqumvHrolfe/2TcuIPCt3K589dhUNiT5OSEh4KoM9Jp1vK2GMnFjDdyaeFMrd06ki1gn9CmEz3OErpebmp+GzyAN+lMLw6dwkKh6Ve5dOnzp4W0+Y25TTfhHB10isXpxIB5GHDKcggnof+NCpCD+okAFyTPNGuRVgahmhLjZo1rnqnMlpD0ORJSluuY6jT+gPWHtaIeDKOaoradNDPruOQzulPGcBtz0C2YdbLrSFPIMGTrcNRDGC3YnJOm1JLceYK2sCWY5lqxICXIEU0gki2nkPFUteBwoqLMyTdKE7ZlOzE3yHfdSyOU2shl8RoxPJlx1bQ6C0Li3DLg+Sdi+c5evEkhtF3rBdfXpe0IiNcfW27+x6u5U4vs8zZZdu1R7Gblyc6AV9OB4Xp65HRDqcvw0Pi1DGbddntOKzYgkbhXJq+Y4bRVqszl746KdRPFV5FxSUb6XmKomd1yCb0nJbpz+aOIZskx0phXx8sHfNKyRjPsM8LGU/xJ9Qrv2JugdVBkBg/ZpUIDvpN0jfHD550XPKNDgkKEZ46l4dwq0sOxIecJlX2pxxA8GTwkCGMFqxVFf5PRZplCky9uCIQL/s/RFabTYZNkhtkQXFR28vKXwKUP5rZbFg+s3VAFTu5dBZG4G07t5tHuM2cFirh2BisrHKYoE8lzO1h/LkwjSD+VZF0qs1hQVK+d0xHOLN80q4B/P9utxQDmGt4DaEKE6Lc5lnI6VxDf/35owQHCAuKw95VG6l1bvXPY3J1slpepPBXdCx8EM+ubbd2tV48b2UtWLtYb89PZhvg2jsq5+zkBdIVVTFHfhEwNv0CxNiT02LKVxGSus1dt9VsXDZulogOJB1AkGQVg4e833uzaWatx7bPrLKyhBeBqlC3xGqNoe3MVQHmDmBs4jm+xFjW/sjcAgOiPOFawwe3bUeTa20vGNZgbV6tCtL/qEL/fmiFLjqCCDpZdQpkdKgx6tSuzlCdqnrMFsLMhWn9sKH4ezmjmvpp9Selw9oCS0Vtcbox4f967yYpc1lNwUzPAUT3N0R32yz0bof5Wblw2jzkuw4VkWFptzoKckHRUwszvHJS8IgkAfys2IvKr/LtZBa1LzvfHBmFD6/V9enLD7LLJD2tz7n3E8BkFcwVyA/DL8P0fCpXAdLntBfy9tQCpuUP2QBAWkwyYccYGYFWWc/HS8Of6pVNf1r8p8n48bn+wPLzm5gyWoneAh3ivzATiiRKljoz8hQTN3S0itSojpnbgvjFod7uBf2Rtsa7dej63gKVRdenkDS2Q9baZyzWY1AZnIBa6yT0juo9eLCWhhOlwxFrCYRVjkKywhfIVrlrLNa3UNngB9RWBQe9mxF1zMGBUFCnRoyUWLBpCStm1SU5sRRFFSeI7HUYtawUeswQzaNk4PKSsmJBL3ERbY4dPD65glIJS5rqxD3kYsThULFbU23ETEuslLobSkuluh1LzKoTkLM0hBH1A1pgJku2CjOVizQ+hUrPP4GQeTkYaS0tarYzCI2HMnusXImyHsZe3dWrxb1U9/CRVaBMggS79TUqJ6yHSSAcdq4Kc9evZUOYUSWsI7LdGpQy7Ul99ZL1qfObT4CedX+zSJGjRBV1NNFGF30MMcYsVugeKLLqDXiNLuQnSQjRvRwtrRzlsSoBxeiSl1SvLVQoF1FcZj0Jqi46odWosl43b1H9Lp2FOAgl7OKibs6cgOICAA==') format('woff2'),
url('iconfont.woff?t=1589437921018') format('woff'),
url('iconfont.ttf?t=1589437921018') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg?t=1589437921018#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-yigouxuan:before {
content: "\e63d";
}
.icon-weigouxuan:before {
content: "\e63e";
}
.icon-weigouxuan1:before {
content: "\e64a";
}
.icon-yigouxuan1:before {
content: "\e64b";
}
.icon-shixiangyoujiantou-:before {
content: "\e626";
}
.icon-shixiangxiajiantou-:before {
content: "\e625";
}
.icon-jiahao:before {
content: "\e72d";
}
.icon-up:before {
content: "\e769";
}
.icon-down:before {
content: "\e76b";
}
.icon-delete:before {
content: "\e6e9";
}
.icon-qq:before {
content: "\e614";
font-size: 60px;
color: #22aaf8;
margin-left: 32px;
}
.icon-weixin:before {
content: "\e68a";
font-size: 60px;
color: #10b747;
margin-right: 32px;
}

Binary file not shown.

File diff suppressed because one or more lines are too long

@ -0,0 +1,93 @@
{
"id": "1540265",
"name": "education",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "2716513",
"name": "已勾选32",
"font_class": "yigouxuan",
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "2716516",
"name": "未勾选32",
"font_class": "weigouxuan",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "2892929",
"name": "未勾选40",
"font_class": "weigouxuan1",
"unicode": "e64a",
"unicode_decimal": 58954
},
{
"icon_id": "2892954",
"name": "已勾选40",
"font_class": "yigouxuan1",
"unicode": "e64b",
"unicode_decimal": 58955
},
{
"icon_id": "5979965",
"name": "实 向右箭头-01",
"font_class": "shixiangyoujiantou-",
"unicode": "e626",
"unicode_decimal": 58918
},
{
"icon_id": "5979966",
"name": "实 向下箭头-01",
"font_class": "shixiangxiajiantou-",
"unicode": "e625",
"unicode_decimal": 58917
},
{
"icon_id": "8349103",
"name": "加号-填充",
"font_class": "jiahao",
"unicode": "e72d",
"unicode_decimal": 59181
},
{
"icon_id": "6129078",
"name": "42指向上、上箭头",
"font_class": "up",
"unicode": "e769",
"unicode_decimal": 59241
},
{
"icon_id": "6129081",
"name": "44指向下、下箭头",
"font_class": "down",
"unicode": "e76b",
"unicode_decimal": 59243
},
{
"icon_id": "410692",
"name": "群蜂删除-充",
"font_class": "delete",
"unicode": "e6e9",
"unicode_decimal": 59113
},
{
"icon_id": "468193",
"name": "qq",
"font_class": "qq",
"unicode": "e614",
"unicode_decimal": 58900
},
{
"icon_id": "7009153",
"name": "微信-36",
"font_class": "weixin",
"unicode": "e68a",
"unicode_decimal": 59018
}
]
}

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

Loading…
Cancel
Save