20240205
yujialong 3 years ago
commit f715901fbe
  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. 5
      src/api/index.js
  12. BIN
      src/assets/img/card-machine.png
  13. BIN
      src/assets/img/cash-sm.png
  14. BIN
      src/assets/img/cash.png
  15. BIN
      src/assets/img/cipher-machine.png
  16. BIN
      src/assets/img/company-finance.png
  17. BIN
      src/assets/img/computer.png
  18. BIN
      src/assets/img/counter.png
  19. BIN
      src/assets/img/credit-dep.png
  20. BIN
      src/assets/img/currency-detector.png
  21. BIN
      src/assets/img/data-frame-checked.png
  22. BIN
      src/assets/img/data-frame.png
  23. BIN
      src/assets/img/dia-title.png
  24. BIN
      src/assets/img/employee.png
  25. BIN
      src/assets/img/glass.png
  26. BIN
      src/assets/img/guide.png
  27. BIN
      src/assets/img/idCard-copy-sm.png
  28. BIN
      src/assets/img/idCard-scanner.png
  29. BIN
      src/assets/img/idCard-sm.png
  30. BIN
      src/assets/img/idCard.png
  31. BIN
      src/assets/img/important.png
  32. BIN
      src/assets/img/integrated-counter-bg.png
  33. BIN
      src/assets/img/integrated-counter.png
  34. BIN
      src/assets/img/international.png
  35. BIN
      src/assets/img/logo.png
  36. BIN
      src/assets/img/man.png
  37. BIN
      src/assets/img/manager.png
  38. BIN
      src/assets/img/money-box.png
  39. BIN
      src/assets/img/open-account-apply-sm.png
  40. BIN
      src/assets/img/open-account.png
  41. BIN
      src/assets/img/personal-finance.png
  42. BIN
      src/assets/img/printer.png
  43. BIN
      src/assets/img/seal-box.png
  44. BIN
      src/assets/img/sth-bg.png
  45. BIN
      src/assets/img/summons.png
  46. BIN
      src/assets/img/tooltip/cpl.png
  47. BIN
      src/assets/img/tooltip/dyj.png
  48. BIN
      src/assets/img/tooltip/mmq.png
  49. BIN
      src/assets/img/tooltip/ptpzx.png
  50. BIN
      src/assets/img/tooltip/qx.png
  51. BIN
      src/assets/img/tooltip/sfz.png
  52. BIN
      src/assets/img/tooltip/skj.png
  53. BIN
      src/assets/img/tooltip/system.png
  54. BIN
      src/assets/img/tooltip/ycj.png
  55. BIN
      src/assets/img/tooltip/yzh.png
  56. BIN
      src/assets/img/tooltip/zk.png
  57. BIN
      src/assets/img/voucher-box.png
  58. 14
      src/assets/svg/arrow-left.svg
  59. 14
      src/assets/svg/arrow-right.svg
  60. 12
      src/assets/svg/checked.svg
  61. 12
      src/assets/svg/close.svg
  62. 124
      src/components/pdf/index.vue
  63. 179
      src/components/quill/index.vue
  64. 16
      src/components/quill/options.js
  65. 30
      src/i18n/index.js
  66. 28
      src/layouts/footer/index.vue
  67. 50
      src/layouts/header/index.vue
  68. 62
      src/layouts/home/index.vue
  69. 123
      src/layouts/navbar/index.vue
  70. 25
      src/libs/auth/generateBtnPermission.js
  71. 6
      src/libs/bus.js
  72. 10
      src/libs/random_str.js
  73. 16
      src/libs/resize/index.js
  74. 32
      src/libs/route/addRoutes.js
  75. 26
      src/libs/route/generateRoutes.js
  76. 6
      src/libs/route/resetRouter.js
  77. 43
      src/libs/util.cookies.js
  78. 83
      src/libs/util.db.js
  79. 136
      src/libs/util.js
  80. 45
      src/main.js
  81. 11
      src/mixins/app.js
  82. 8
      src/mixins/setBackground/index.js
  83. 59
      src/pages/exception/error/403/index.vue
  84. 59
      src/pages/exception/error/404/index.vue
  85. 46
      src/pages/exception/i18n/index.vue
  86. 225
      src/pages/exception/icon/index.vue
  87. 404
      src/pages/index/list/index.vue
  88. 1
      src/plugins/aliplayer/aliplayer-min.css
  89. 2
      src/plugins/aliplayer/aliplayer-min.js
  90. 25
      src/plugins/auth/index.js
  91. 12
      src/plugins/filters/index.js
  92. 14
      src/plugins/index.js
  93. 146
      src/plugins/requests/index.js
  94. 18
      src/plugins/throttle/index.js
  95. 22
      src/router/index.js
  96. 23
      src/router/modules/data.js
  97. 23
      src/router/modules/index.js
  98. 23
      src/router/modules/role.js
  99. 23
      src/router/modules/setting.js
  100. 23
      src/router/modules/stat.js
  101. Some files were not shown because too many files have changed in this diff Show More

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

22
.gitignore vendored

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

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

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

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

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 () {
//localStorage
if (util.local.get(Setting.storeKey) ) {
this.$store.replaceState(Object.assign({}, this.$store.state,util.local.get(Setting.storeKey)))
}
//vuexlocalStorage
window.addEventListener("beforeunload",()=>{
util.local.get(Setting.tokenKey) && util.local.set(Setting.storeKey,this.$store.state)
})
}
}
</script>

@ -0,0 +1,5 @@
export default {
// 登录注册
logins: `/users/users/user/login`,
verification:`/users/users/user/captcha`,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59 (86127) - https://sketch.com -->
<title>图标 / 物品栏 / 收起</title>
<desc>Created with Sketch.</desc>
<g id="图标-/-物品栏-/-收起" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标-/-弹窗-/-关闭">
<g>
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<polyline id="形状结合" stroke="#FFFFFF" stroke-width="3" stroke-linecap="round" points="15 19 8 12 15 5"></polyline>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 754 B

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59 (86127) - https://sketch.com -->
<title>图标 / 物品栏 / 展开</title>
<desc>Created with Sketch.</desc>
<g id="图标-/-物品栏-/-展开" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图标-/-物品栏-/-收起">
<g id="图标-/-弹窗-/-关闭" transform="translate(12.000000, 12.000000) scale(-1, 1) translate(-12.000000, -12.000000) ">
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<polyline id="形状结合" stroke="#FFFFFF" stroke-width="3" stroke-linecap="round" points="15 19 8 12 15 5"></polyline>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 879 B

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59 (86127) - https://sketch.com -->
<title>图标 / 多选 / 选中</title>
<desc>Created with Sketch.</desc>
<g id="图标-/-多选-/-选中" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g>
<path d="M7.6916556,-3.10752092e-16 L16.3083444,3.10752092e-16 C18.9829006,-1.80555915e-16 19.9527593,0.278476833 20.9305371,0.801398111 C21.9083149,1.32431939 22.6756806,2.09168511 23.1986019,3.06946289 C23.7215232,4.04724067 24,5.01709938 24,7.6916556 L24,16.3083444 C24,18.9829006 23.7215232,19.9527593 23.1986019,20.9305371 C22.6756806,21.9083149 21.9083149,22.6756806 20.9305371,23.1986019 C19.9527593,23.7215232 18.9829006,24 16.3083444,24 L7.6916556,24 C5.01709938,24 4.04724067,23.7215232 3.06946289,23.1986019 C2.09168511,22.6756806 1.32431939,21.9083149 0.801398111,20.9305371 C0.278476833,19.9527593 1.2037061e-16,18.9829006 -2.07168062e-16,16.3083444 L2.07168062e-16,7.6916556 C-1.2037061e-16,5.01709938 0.278476833,4.04724067 0.801398111,3.06946289 C1.32431939,2.09168511 2.09168511,1.32431939 3.06946289,0.801398111 C4.04724067,0.278476833 5.01709938,1.80555915e-16 7.6916556,-3.10752092e-16 Z" id="矩形" fill="#6191FF"></path>
<path d="M10.2421207,12.8440672 L8.61176326,11.1976868 C7.97888708,10.5585907 6.94774987,10.5535485 6.30865384,11.1864247 L6.19066906,11.3161348 C5.65636363,11.9688586 5.69195265,12.9319162 6.29745674,13.5433 L8.26865576,15.5336404 C9.34819137,16.6236589 11.1069624,16.6321569 12.1958476,15.5537491 L18.3693401,9.32088172 C19.0126472,8.67136119 19.0126933,7.62486898 18.3694433,6.97529184 C17.7738724,6.37386276 16.8255587,6.33401491 16.1832994,6.85897251 L16.0666232,6.96402166 L10.2421207,12.8440672 Z" id="路径" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59 (86127) - https://sketch.com -->
<title>图标 / 弹窗 / 关闭</title>
<desc>Created with Sketch.</desc>
<g id="图标-/-弹窗-/-关闭" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g>
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<path d="M5,5 L19,19 M5,19 L19,5" id="形状结合" stroke="#000000" stroke-width="2" opacity="0.502116612" stroke-linecap="round"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 694 B

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

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

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

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

@ -0,0 +1,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,50 @@
<template>
<div class="header">
<div class="inner">
<div class="logo" @click="toIndex">
<img src="../../assets/img/logo.png" alt="">
</div>
</div>
</div>
</template>
<script>
import { mapState,mapActions } from 'vuex'
import Setting from '@/setting'
import util from '@/libs/util'
export default {
data() {
return {
token: util.local.get(Setting.tokenKey),
};
},
mounted(){
},
methods: {
toIndex(){
this.$refs.nav.jump({
index: '/index/list',
title: '首页'
})
},
},
};
</script>
<style lang="scss" scoped>
.header{
z-index: 1;
display: flex;
align-items: center;
position: relative;
height: 68px;
background-color: #fff;
.logo{
width: 500px;
margin-left: 42px;
cursor: pointer;
img{
width: 100%;
}
}
}
</style>

@ -0,0 +1,62 @@
<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%;
}
</style>

@ -0,0 +1,123 @@
<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,mapActions } from 'vuex'
import addRoutes from '@/libs/route/addRoutes'
import Setting from '@/setting'
import util from '@/libs/util'
export default {
data() {
return {
managerStr: this.$route.query.mg,
isManager: false,
active: this.$route.path,
defaultMenus: [
{
index: '/index/list',
title: '首页'
},{
index: '/data/list',
title: '数据'
}
],
managerMenus: [
{
index: '/stat/list',
title: '数据统计'
},{
index: '/user/list',
title: '用户管理'
},{
index: '/role/list',
title: '角色权限'
}
],
menus: [],
actives: {}
};
},
computed: {
...mapState('auth', [
'routes'
])
},
watch: {
'$route'(to,from) {
let actives = this.actives
for(let i in this.actives){
if(actives[i].includes(this.$route.name)) this.active = `/${i}/list`
}
this.active = this.$route.path
}
},
mounted() {
if(util.local.get(Setting.tokenKey)){
this.getPer()
if(this.managerStr && atob(decodeURI(this.managerStr)) === 'true'){
this.isManager = true
this.setManager(false)
}
}
},
methods: {
...mapActions('user', [
'setManager'
]),
initMenu(){
if(this.isManager){
this.defaultMenus = this.managerMenus
if(Setting.dynamicRoute){
let routes = this.routes
let menus = []
this.defaultMenus.map(e => {
routes.find(n => n.name == e.index) && menus.push(e)
})
this.menus = menus
}else{
this.menus = this.defaultMenus
}
}else{
this.menus = this.defaultMenus
}
},
jump(item){
this.active = item.index
this.$router.push(item.index).catch(err => {})
},
getPer(){
this.$post(this.api.getPermissions).then(res => {
let routes = res.permissions[0].children
Setting.dynamicRoute && addRoutes(routes)
this.initMenu()
}).catch(err => {})
},
}
};
</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,25 @@
/**
* @description 生成按钮级别权限组
* */
import store from '@/store';
export default function(data){
let result = []
data.map(e => {
if(e.select){
e.children.map(n => {
if(n.select){
if(n.children.length){
result.push(`${e.name}:${n.name}`)
n.children.map(j => {
j.select && (e.path ? result.push(`${e.path}:${n.name}:${j.name}`) : result.push(`${n.path}:${j.name}`))
})
}else{
result.push(`${e.path}:${n.name}`)
}
}
})
}
})
store.dispatch('auth/addBtnAuth',result)
}

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

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

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

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

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

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

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

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

@ -0,0 +1,136 @@
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()
},
// 传入文件名和数据,下载文件
downloadFileDirect(fileName,data) {
if ('download' in document.createElement('a')) { // 非IE下载
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(data)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href) // 释放URL 对象
document.body.removeChild(elink)
} else { // IE10+下载
navigator.msSaveBlob(data, fileName)
}
},
// 成功提示
successMsg(message,duration = 3000) {
return Message.success({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration})
},
// 警告提示
warningMsg(message,duration = 3000) {
return Message.warning({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration})
},
// 错误提示
errorMsg(message,duration = 3000) {
return Message.error({message,showClose: true,offset: (document.documentElement.clientHeight - 40) / 2,duration})
},
}
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,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,404 @@
<template>
<div class="wrap">
<img class="sth bg" src="@/assets/img/integrated-counter-bg.png" alt="">
<img class="sth guide" src="@/assets/img/guide.png" alt="">
<img class="sth man" src="@/assets/img/man.png" alt="">
<img class="sth counter" src="@/assets/img/counter.png" alt="">
<img class="sth glass" src="@/assets/img/glass.png" alt="">
<el-tooltip placement="top" popper-class="sth-popper">
<div slot="content">
<img style="height: 145px" src="@/assets/img/tooltip/system.png" alt="">
</div>
<img class="sth computer cp" src="@/assets/img/computer.png" alt="">
</el-tooltip>
<el-tooltip placement="top" popper-class="sth-popper" offset="50">
<div slot="content">
<img src="@/assets/img/tooltip/cpl.png" alt="">
</div>
<img class="sth summons cp" src="@/assets/img/summons.png" alt="">
</el-tooltip>
<el-tooltip placement="top-start" popper-class="sth-popper" offset="250">
<div slot="content">
<img src="@/assets/img/tooltip/ptpzx.png" alt="">
</div>
<img class="sth voucher-box cp" src="@/assets/img/voucher-box.png" alt="">
</el-tooltip>
<el-tooltip placement="top-start" popper-class="sth-popper" offset="250">
<div slot="content">
<img src="@/assets/img/tooltip/zk.png" alt="">
</div>
<img class="sth important cp" src="@/assets/img/important.png" alt="">
</el-tooltip>
<el-tooltip placement="left-start" popper-class="sth-popper">
<div slot="content">
<img src="@/assets/img/tooltip/qx.png" alt="">
</div>
<img class="sth money-box cp" src="@/assets/img/money-box.png" alt="" @click="showData('钱箱')">
</el-tooltip>
<el-tooltip placement="top" popper-class="sth-popper" offset="-100">
<div slot="content">
<img src="@/assets/img/tooltip/yzh.png" alt="">
</div>
<img class="sth seal-box cp" src="@/assets/img/seal-box.png" alt="">
</el-tooltip>
<el-tooltip placement="top" popper-class="sth-popper" offset="-100">
<div slot="content">
<img src="@/assets/img/tooltip/ycj.png" alt="">
</div>
<img class="sth currency-detector cp" src="@/assets/img/currency-detector.png" alt="">
</el-tooltip>
<el-tooltip placement="top" popper-class="sth-popper" offset="-400">
<div slot="content">
<img src="@/assets/img/tooltip/dyj.png" alt="">
</div>
<img class="sth printer cp" src="@/assets/img/printer.png" alt="">
</el-tooltip>
<el-tooltip placement="top" popper-class="sth-popper" offset="50">
<div slot="content">
<img src="@/assets/img/tooltip/mmq.png" alt="">
</div>
<img class="sth cipher-machine cp" src="@/assets/img/cipher-machine.png" alt="">
</el-tooltip>
<img class="sth employee" src="@/assets/img/employee.png" alt="">
<el-tooltip placement="top" popper-class="sth-popper" offset="50">
<div slot="content">
<img src="@/assets/img/tooltip/skj.png" alt="">
</div>
<img class="sth card-machine cp" src="@/assets/img/card-machine.png" alt="">
</el-tooltip>
<el-tooltip placement="top" popper-class="sth-popper" offset="-100">
<div slot="content">
<img src="@/assets/img/tooltip/sfz.png" alt="">
</div>
<img class="sth idCard-scanner cp" src="@/assets/img/idCard-scanner.png" alt="">
</el-tooltip>
<div class="goods-dia" :class="{active: showGoods}">
<img src="@/assets/img/idCard.png" alt="">
<img src="@/assets/img/open-account.png" alt="">
<img src="@/assets/img/cash.png" alt="">
</div>
<div class="goods" :class="{active: showGoods}" @click="toggleGoods">
<span>物品栏</span>
<img class="icon" src="@/assets/svg/arrow-right.svg" alt="">
</div>
<el-dialog :visible.sync="dataVisible" width="1280px" @close="closeData" :close-on-click-modal="false" :show-close="false" custom-class="data-dia">
<div slot="title" class="dia-header">
<div class="data-title">{{dataTitle}}</div>
<img class="close" src="@/assets/svg/close.svg" alt="" @click="closeDataDia">
</div>
<p class="tips">- 请单击选中所需材料双击可放大预览 -</p>
<ul class="list">
<li :class="{checked: checkList.includes(1)}" @click="checkData(1)">
<img src="@/assets/img/idCard-sm.png" alt="">
<p>身份证</p>
</li>
<li :class="{checked: checkList.includes(2)}" @click="checkData(2)">
<img src="@/assets/img/idCard-copy-sm.png" alt="">
<p>身份证复印件</p>
</li>
<li :class="{checked: checkList.includes(3)}" @click="checkData(3)">
<img style="margin-top: 0" src="@/assets/img/open-account-apply-sm.png" alt="">
<p>开户申请书</p>
</li>
<li :class="{checked: checkList.includes(4)}" @click="checkData(4)">
<img style="margin-top: 32px" src="@/assets/img/cash-sm.png" alt="">
<p>现金</p>
</li>
</ul>
<div class="dia-footer">
<button type="button">确定</button>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'index',
data() {
return {
showGoods: false,
dataTitle: '',
dataVisible: false,
checkList: []
}
},
watch: {
},
mounted() {
},
methods: {
toggleGoods(){
this.showGoods = !this.showGoods
},
showData(type){
this.dataTitle = type
this.dataVisible = true
},
checkData(id){
this.checkList.includes(id) ? this.checkList.splice(this.checkList.indexOf(id),1) : this.checkList.push(id)
},
closeDataDia(){
this.dataVisible = false
},
closeData(){
this.checkList = []
}
}
};
</script>
<style lang="scss" scoped>
.wrap{
// position: relative;
// min-height: calc(100vh - 68px);
.sth{
position: absolute;
&.cp{
cursor: pointer;
}
}
.guide{
top: 90px;
left: 0;
width: 222px;
cursor: pointer;
&:hover{
opacity: .9;
}
}
.bg{
top: 0;
left: 0;
width: 100%;
}
.counter{
top: 116px;
left: 357px;
width: 1555px;
}
.glass{
top: -135px;
left: 956px;
width: 50%;
}
.employee{
top: 371px;
left: 920px;
width: 388px;
}
.man{
top: 82px;
right: 150px;
width: 262px;
}
.money-box{
top: 406px;
left: 445px;
width: 197px;
}
.important{
top: 372px;
left: 582px;
width: 175px;
}
.voucher-box{
top: 216px;
left: 718px;
width: 160px;
}
.summons{
top: 250px;
left: 844px;
width: 139px;
}
.computer{
top: 120px;
left: 955px;
width: 219px;
}
.card-machine{
top: 377px;
left: 1147px;
width: 110px;
}
.idCard-scanner{
top: 443px;
left: 1229px;
width: 82px;
}
.seal-box{
top: 486px;
left: 1340px;
width: 97px;
}
.currency-detector{
top: 492px;
left: 1421px;
width: 151px;
}
.printer{
top: 550px;
left: 1531px;
width: 205px;
}
.cipher-machine{
top: 324px;
left: 1298px;
width: 100px;
}
.goods{
position: fixed;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 94px;
height: 200px;
cursor: pointer;
background: url(../../../assets/img/sth-bg.png) 0 0/cover no-repeat;
span{
width: 30px;
margin-bottom: 10px;
color: #fff;
font-size: 30px;
text-align: center;
}
.icon{
width: 30px;
transition: all .5s;
}
&:hover{
opacity: .9;
}
&.active{
.icon{
transform: rotate(180deg);
}
}
}
.goods-dia{
display: flex;
position: fixed;
bottom: 0;
left: -100%;
justify-content: center;
align-items: center;
width: 100%;
padding: 20px 0;
transition: all .5s;
background-color: rgba(255,255,255,.7);
&.active{
left: 0;
}
img{
margin-right: 50px;
&:last-child{
margin-right: 0;
}
}
}
}
/deep/.data-dia{
border-radius: 16px;
.el-dialog__header{
padding: 0;
border-bottom: 0;
.dia-header{
position: relative;
.data-title{
width: 300px;
margin: 0 auto;
line-height: 72px;
text-align: center;
color: #fff;
font-size: 24px;
background: url(../../../assets/img/dia-title.png) 0 0/cover no-repeat;
}
.close{
position: absolute;
top: 15px;
right: 15px;
cursor: pointer;
}
}
}
.tips{
margin: 20px 0 100px;
text-align: center;
font-size: 20px;
color: #000;
}
.list{
width: 940px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
li{
position: relative;
width: 204px;
height: 204px;
text-align: center;
background: url(../../../assets/img/data-frame.png) 0 0/cover no-repeat;
cursor: pointer;
img{
margin-top: 45px;
}
p{
position: absolute;
bottom: 0;
width: 100%;
line-height: 54px;
text-align: center;
font-size: 18px;
color: #000;
}
&.checked{
background: url(../../../assets/img/data-frame-checked.png) 0 0/cover no-repeat,
url(../../../assets/svg/checked.svg) 165px 7%/auto no-repeat;
p{
color: #fff;
}
}
}
}
.dia-footer{
margin-top: 140px;
text-align: center;
button{
width: 300px;
line-height: 60px;
color: #fff;
font-size: 24px;
background-color: rgb(81,147,255);
border: 0;
border-radius: 20px;
cursor: pointer;
&:hover{
opacity: .9;
}
}
}
}
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

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

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

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

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

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

@ -0,0 +1,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: '数据统计' }
},
]
};

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

Loading…
Cancel
Save