├── .browserslistrc ├── .gitignore ├── .prettierrc ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── index.html └── static │ ├── dataV.png │ ├── login.png │ └── slogan.png ├── src ├── App.vue ├── api │ ├── admin.js │ ├── common.js │ ├── log.js │ ├── menu.js │ └── role.js ├── assets │ ├── css │ │ ├── bootstrap.min.css │ │ ├── color-dark.css │ │ ├── icon.css │ │ ├── iconfont.css │ │ ├── main.css │ │ └── theme-green │ │ │ ├── color-green.css │ │ │ ├── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ │ │ └── index.css │ ├── img │ │ ├── background.png │ │ ├── img.jpg │ │ ├── login.jpg │ │ ├── processed.png │ │ ├── slogan.png │ │ └── undisposed.png │ └── js │ │ ├── bus.js │ │ ├── china.js │ │ ├── common.js │ │ ├── directives.js │ │ ├── i18n.js │ │ ├── jquery.countup.min.js │ │ ├── jquery.min.js │ │ ├── jquery.waypoints.min.js │ │ ├── order.json │ │ └── sale.json ├── components │ └── Drawer.vue ├── main.js ├── router │ └── index.js ├── utils │ ├── common.js │ └── request.js ├── vendor │ ├── Blob.js │ └── Export2Excel.js └── views │ ├── admin │ ├── Create.vue │ ├── Edit.vue │ └── Index.vue │ ├── common │ ├── 403.vue │ ├── ChangePassword.vue │ ├── Dashboard.vue │ ├── Header.vue │ ├── Home.vue │ ├── Login.vue │ ├── Sidebar.vue │ └── Tags.vue │ ├── component │ ├── Clipboard.vue │ └── Upload.vue │ ├── log │ ├── Error.vue │ ├── Login.vue │ └── Request.vue │ ├── menu │ ├── Create.vue │ ├── Edit.vue │ └── Index.vue │ └── role │ ├── Create.vue │ ├── Edit.vue │ └── Index.vue └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 140 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## vue-admin 2 | 该项目基于 vue.js,使用 vue-cli3 脚手架,引用 Element UI 组件库、Echarts、视频上传至七牛云、抽屉组件、剪切板、导出Excel等,作为一套基础的后台系统,适用于绝大部分的后台管理系统开发;包含:登录、注销、可视化数据大屏、管理员、角色管理、菜单管理、权限管理、错误日志、登录日志、访问日志等功能;需要配合后端接口一起使用。 3 | 4 | 5 | ## 功能 6 | - [x] 登录/注销 7 | - [x] 可视化数据大屏 8 | - [x] 管理员 9 | - [x] 角色管理 10 | - [x] 菜单管理 11 | - [x] 权限管理 12 | - [x] 错误日志 13 | - [x] 登录日志 14 | - [x] 访问日志 15 | - [x] 视频上传至七牛云 16 | - [x] 抽屉组件 17 | - [x] 剪切板 18 | - [x] 导出Excel 19 | 20 | 21 | 22 | ## 项目截图 23 | ##### 登录界面 24 | ![](https://sobj.oss-cn-beijing.aliyuncs.com/image/20201022/login.png) 25 | ##### 数据大屏 26 | ![](https://sobj.oss-cn-beijing.aliyuncs.com/image/20201022/dataV.png) 27 | ##### 菜单管理 28 | ![](https://sobj.oss-cn-beijing.aliyuncs.com/image/20201130/menu.png) 29 | ##### 权限管理 30 | ![](https://sobj.oss-cn-beijing.aliyuncs.com/image/20201130/permission.png) 31 | ##### 错误日志 32 | ![](https://sobj.oss-cn-beijing.aliyuncs.com/image/20201130/error.png) 33 | 34 | 35 | ## 安装步骤 36 | - git clone https://github.com/wdjisn/vue-admin.git 37 | - cd 代码目录 38 | - npm install 39 | - npm run serve 40 | - 浏览器访问:http://localhost:8080 41 | 42 | 43 | ## 后端仓库 44 | - https://github.com/wdjisn/laravel-admin.git 45 | 46 | 47 | ## 在线体验 48 | - 网址:http://laravel.baobaonames.cn/#/login 49 | - 账号:style 50 | - 密码:123456 51 | 52 | 53 | ## 疑问解答 54 | - 微信:wdjisn 55 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-style-admin", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "npm run serve", 7 | "serve": "vue-cli-service serve", 8 | "build": "vue-cli-service build" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.18.0", 12 | "babel-polyfill": "^6.26.0", 13 | "echarts": "^4.2.1", 14 | "element-ui": "^2.11.0", 15 | "file-saver": "^2.0.2", 16 | "js-base64": "^2.5.2", 17 | "js-md5": "^0.7.3", 18 | "qiniu": "^7.1.3", 19 | "script-loader": "^0.7.2", 20 | "vue": "^2.6.10", 21 | "vue-clipboard2": "^0.3.1", 22 | "vue-cropperjs": "^3.0.0", 23 | "vue-i18n": "^8.10.0", 24 | "vue-router": "^3.0.3", 25 | "xlsx": "^0.16.1" 26 | }, 27 | "devDependencies": { 28 | "@vue/cli-plugin-babel": "^3.9.0", 29 | "@vue/cli-service": "^3.9.0", 30 | "node-sass": "^4.14.1", 31 | "qiniu-js": "^1.0.24", 32 | "sass-loader": "^10.0.2", 33 | "vue-template-compiler": "^2.6.10" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Vue Style Admin 11 | 12 | 13 | 14 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /public/static/dataV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/public/static/dataV.png -------------------------------------------------------------------------------- /public/static/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/public/static/login.png -------------------------------------------------------------------------------- /public/static/slogan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/public/static/slogan.png -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/api/admin.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request'; 2 | 3 | // 获取管理员列表 4 | export function adminList(data) { return request({ url: '/admins', method: 'get', params: data })} 5 | 6 | // 添加管理员 7 | export function createAdmin(data) { return request({ url: '/admin', method: 'post', data })} 8 | 9 | // 编辑管理员 10 | export function editAdmin(data) { return request({ url: '/admin', method: 'put', data })} 11 | 12 | // 快捷修改管理员 13 | export function quickEditAdmin(data) { return request({ url: '/admin', method: 'patch', data })} 14 | 15 | // 删除管理员 16 | export function delAdmin(data) { return request({ url: '/admin', method: 'delete', data })} -------------------------------------------------------------------------------- /src/api/common.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request'; 2 | 3 | // 登录 4 | export function login(data) { return request({ url: '/login', method: 'post', data })} 5 | 6 | // 获取权限 7 | export function permission(data) { return request({ url: '/permission', method: 'get', params: data })} 8 | 9 | // 修改密码 10 | export function changePassword(data) { return request({ url: '/change/password', method: 'put', data })} -------------------------------------------------------------------------------- /src/api/log.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request'; 2 | 3 | // 获取登录日志 4 | export function loginLog(data) { return request({ url: '/login/logs', method: 'get', params: data })} 5 | 6 | // 获取错误日志 7 | export function errorLog(data) { return request({ url: '/error/logs', method: 'get', params: data })} 8 | 9 | // 编辑错误日志 10 | export function editLog(data) { return request({ url: '/error/log', method: 'put', data })} 11 | 12 | // 获取访问日志 13 | export function requestLog(data) { return request({ url: '/request/logs', method: 'get', params: data })} -------------------------------------------------------------------------------- /src/api/menu.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request'; 2 | 3 | // 获取菜单列表 4 | export function menuList(data) { return request({ url: '/menus', method: 'get', params: data })} 5 | 6 | // 获取树形菜单 7 | export function menuTree(data) { return request({ url: '/menu/tree', method: 'get', params: data })} 8 | 9 | // 添加菜单 10 | export function createMenu(data) { return request({ url: '/menu', method: 'post', data })} 11 | 12 | // 编辑菜单 13 | export function editMenu(data) { return request({ url: '/menu', method: 'put', data })} 14 | 15 | // 快捷修改菜单 16 | export function quickEditMenu(data) { return request({ url: '/menu', method: 'patch', data })} 17 | 18 | // 删除菜单 19 | export function delMenu(data) { return request({ url: '/menu', method: 'delete', data })} -------------------------------------------------------------------------------- /src/api/role.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request'; 2 | 3 | // 获取角色列表 4 | export function roleList(data) { return request({ url: '/roles', method: 'get', params: data })} 5 | 6 | // 获取角色详情 7 | export function roleInfo(data) { return request({ url: '/role', method: 'get', params: data })} 8 | 9 | // 添加角色 10 | export function createRole(data) { return request({ url: '/role', method: 'post', data })} 11 | 12 | // 编辑角色 13 | export function editRole(data) { return request({ url: '/role', method: 'put', data })} 14 | 15 | // 快捷修改角色 16 | export function quickEditRole(data) { return request({ url: '/role', method: 'patch', data })} 17 | 18 | // 删除角色 19 | export function delRole(data) { return request({ url: '/role', method: 'delete', data })} -------------------------------------------------------------------------------- /src/assets/css/color-dark.css: -------------------------------------------------------------------------------- 1 | .header { 2 | background-color: #ffffff; 3 | } 4 | 5 | .login-wrap { 6 | background: #324157; 7 | } 8 | 9 | .plugins-tips { 10 | background: #eef1f6; 11 | } 12 | 13 | .plugins-tips a { 14 | color: #20a0ff; 15 | } 16 | 17 | .el-upload--text em { 18 | color: #20a0ff; 19 | } 20 | 21 | .pure-button { 22 | background: #20a0ff; 23 | } 24 | 25 | .tags-li.active { 26 | border: 1px solid #409EFF; 27 | background-color: #409EFF; 28 | } 29 | 30 | .message-title { 31 | color: #20a0ff; 32 | } 33 | 34 | /* .collapse-btn:hover{ 35 | background: rgb(40,52,70); 36 | } */ -------------------------------------------------------------------------------- /src/assets/css/icon.css: -------------------------------------------------------------------------------- 1 | 2 | [class*=" el-icon-lx"], [class^=el-icon-lx] { 3 | font-family: lx-iconfont!important; 4 | } -------------------------------------------------------------------------------- /src/assets/css/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face {font-family: "iconfont"; 2 | src: url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2') 3 | } 4 | 5 | .iconfont { 6 | font-family: "iconfont" !important; 7 | font-size: 16px; 8 | font-style: normal; 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | 13 | .icon-SCMliucheng:before { 14 | content: "\e602"; 15 | } 16 | 17 | .icon-baobiao:before { 18 | content: "\e605"; 19 | } 20 | 21 | .icon-toupiao:before { 22 | content: "\e608"; 23 | } 24 | 25 | .icon-xinjian:before { 26 | content: "\e614"; 27 | } 28 | 29 | .icon-shezhi:before { 30 | content: "\e61b"; 31 | } 32 | 33 | .icon-dingyue:before { 34 | content: "\e623"; 35 | } 36 | 37 | .icon-yuansu:before { 38 | content: "\e626"; 39 | } 40 | 41 | .icon-huiyi:before { 42 | content: "\e62f"; 43 | } 44 | 45 | .icon-qianbao:before { 46 | content: "\e630"; 47 | } 48 | 49 | .icon-jiyao:before { 50 | content: "\e631"; 51 | } 52 | 53 | .icon-zhanghu:before { 54 | content: "\e632"; 55 | } 56 | 57 | .icon-liulan:before { 58 | content: "\e633"; 59 | } 60 | 61 | .icon-zhishizhongxin:before { 62 | content: "\e634"; 63 | } 64 | 65 | .icon-xiangmu:before { 66 | content: "\e63d"; 67 | } 68 | 69 | .icon-shuju:before { 70 | content: "\e63e"; 71 | } 72 | 73 | .icon-xuqiu:before { 74 | content: "\e641"; 75 | } 76 | 77 | .icon-wendangzhongxin:before { 78 | content: "\e645"; 79 | } 80 | 81 | .icon-renwu:before { 82 | content: "\e64a"; 83 | } 84 | 85 | .icon-liucheng:before { 86 | content: "\e64c"; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /src/assets/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | html, 7 | body, 8 | #app, 9 | .wrapper { 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | } 14 | 15 | body { 16 | font-size: 12px; 17 | font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif; 18 | } 19 | 20 | a { 21 | text-decoration: none 22 | } 23 | 24 | 25 | .content-box { 26 | position: absolute; 27 | left: 205px; 28 | right: 0; 29 | top: 0px; 30 | bottom: 0; 31 | padding-bottom: 30px; 32 | -webkit-transition: left .3s ease-in-out; 33 | transition: left .3s ease-in-out; 34 | background: #f0f0f0; 35 | } 36 | 37 | .content { 38 | width: auto; 39 | height: 100%; 40 | padding: 10px; 41 | overflow-y: scroll; 42 | box-sizing: border-box; 43 | } 44 | 45 | .content-collapse { 46 | left: 64px; 47 | } 48 | 49 | .container { 50 | padding: 30px; 51 | background: #fff; 52 | border: 1px solid #ddd; 53 | border-radius: 5px; 54 | } 55 | 56 | .crumbs { 57 | margin: 10px 0; 58 | } 59 | 60 | .el-table th { 61 | background-color: #f5f7fa !important; 62 | } 63 | 64 | .pagination { 65 | margin: 20px 0; 66 | text-align: right; 67 | } 68 | 69 | .plugins-tips { 70 | padding: 20px 10px; 71 | margin-bottom: 20px; 72 | } 73 | 74 | .el-button+.el-tooltip { 75 | margin-left: 10px; 76 | } 77 | 78 | .el-table tr:hover { 79 | background: #f6faff; 80 | } 81 | 82 | .mgb20 { 83 | margin-bottom: 20px; 84 | } 85 | 86 | .move-enter-active, 87 | .move-leave-active { 88 | transition: opacity .5s; 89 | } 90 | 91 | .move-enter, 92 | .move-leave { 93 | opacity: 0; 94 | } 95 | 96 | /*BaseForm*/ 97 | 98 | .form-box { 99 | width: 600px; 100 | } 101 | 102 | .form-box .line { 103 | text-align: center; 104 | } 105 | 106 | .el-time-panel__content::after, 107 | .el-time-panel__content::before { 108 | margin-top: -7px; 109 | } 110 | 111 | .el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) { 112 | padding-bottom: 0; 113 | } 114 | 115 | /*Upload*/ 116 | 117 | .pure-button { 118 | width: 150px; 119 | height: 40px; 120 | line-height: 40px; 121 | text-align: center; 122 | color: #fff; 123 | border-radius: 3px; 124 | } 125 | 126 | .g-core-image-corp-container .info-aside { 127 | height: 45px; 128 | } 129 | 130 | .el-upload--text { 131 | background-color: #fff; 132 | border: 1px dashed #d9d9d9; 133 | border-radius: 6px; 134 | box-sizing: border-box; 135 | width: 360px; 136 | height: 180px; 137 | text-align: center; 138 | cursor: pointer; 139 | position: relative; 140 | overflow: hidden; 141 | } 142 | 143 | .el-upload--text .el-icon-upload { 144 | font-size: 67px; 145 | color: #97a8be; 146 | margin: 40px 0 16px; 147 | line-height: 50px; 148 | } 149 | 150 | .el-upload--text { 151 | color: #97a8be; 152 | font-size: 14px; 153 | text-align: center; 154 | } 155 | 156 | .el-upload--text em { 157 | font-style: normal; 158 | } 159 | 160 | /*VueEditor*/ 161 | 162 | .ql-container { 163 | min-height: 400px; 164 | } 165 | 166 | .ql-snow .ql-tooltip { 167 | transform: translateX(117.5px) translateY(10px) !important; 168 | } 169 | 170 | .editor-btn { 171 | margin-top: 20px; 172 | } 173 | 174 | .v-note-wrapper .v-note-panel { 175 | min-height: 500px; 176 | } 177 | 178 | .el-button--small, 179 | .el-button--small.is-round { 180 | padding: 6.5px 5.5px !important; 181 | } 182 | 183 | .dialog-footer { 184 | display: flex; 185 | justify-content: flex-end; 186 | } 187 | 188 | .el-table { 189 | font-size: 12px !important; 190 | color:#606266 !important; 191 | } 192 | 193 | .el-form-item__label { 194 | font-size: 12px !important; 195 | color:#606266 !important; 196 | } -------------------------------------------------------------------------------- /src/assets/css/theme-green/color-green.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #07c4a8; 3 | } 4 | .login-wrap{ 5 | background: rgba(56, 157, 170, 0.82);; 6 | } 7 | .plugins-tips{ 8 | background: #f2f2f2; 9 | } 10 | .plugins-tips a{ 11 | color: #00d1b2; 12 | } 13 | .el-upload--text em { 14 | color: #00d1b2; 15 | } 16 | .pure-button{ 17 | background: #00d1b2; 18 | } 19 | .pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus { 20 | background-color: #00d1b2 !important; 21 | border-color: #00d1b2 !important; 22 | } 23 | .tags-li.active { 24 | border: 1px solid #00d1b2; 25 | background-color: #00d1b2; 26 | } 27 | .collapse-btn:hover{ 28 | background: #00d1b2; 29 | } -------------------------------------------------------------------------------- /src/assets/css/theme-green/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/css/theme-green/fonts/element-icons.ttf -------------------------------------------------------------------------------- /src/assets/css/theme-green/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/css/theme-green/fonts/element-icons.woff -------------------------------------------------------------------------------- /src/assets/img/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/img/background.png -------------------------------------------------------------------------------- /src/assets/img/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/img/img.jpg -------------------------------------------------------------------------------- /src/assets/img/login.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/img/login.jpg -------------------------------------------------------------------------------- /src/assets/img/processed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/img/processed.png -------------------------------------------------------------------------------- /src/assets/img/slogan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/img/slogan.png -------------------------------------------------------------------------------- /src/assets/img/undisposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdjisn/vue-admin/04235e467e78484f4be3e8f5ec278a09881ed4e0/src/assets/img/undisposed.png -------------------------------------------------------------------------------- /src/assets/js/bus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | // 使用 Event Bus 4 | const bus = new Vue(); 5 | 6 | export default bus; -------------------------------------------------------------------------------- /src/assets/js/common.js: -------------------------------------------------------------------------------- 1 | // 日期格式化 2 | export const formatDate = (date, fmt) => { 3 | if (/(y+)/.test(fmt)) { 4 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) 5 | } 6 | let o = { 7 | 'M+': date.getMonth() + 1, 8 | 'd+': date.getDate(), 9 | 'h+': date.getHours(), 10 | 'm+': date.getMinutes(), 11 | 's+': date.getSeconds() 12 | } 13 | for (let k in o) { 14 | if (new RegExp(`(${k})`).test(fmt)) { 15 | let str = o[k] + '' 16 | fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str)) 17 | } 18 | } 19 | return fmt 20 | } 21 | 22 | function padLeftZero(str) { 23 | return ('00' + str).substr(str.length) 24 | } -------------------------------------------------------------------------------- /src/assets/js/directives.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | // v-dialogDrag: 弹窗拖拽属性 4 | Vue.directive('dialogDrag', { 5 | bind(el, binding, vnode, oldVnode) { 6 | const dialogHeaderEl = el.querySelector('.el-dialog__header'); 7 | const dragDom = el.querySelector('.el-dialog'); 8 | 9 | dialogHeaderEl.style.cssText += ';cursor:move;' 10 | dragDom.style.cssText += ';top:0px;' 11 | 12 | // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); 13 | const sty = (() => { 14 | if (window.document.currentStyle) { 15 | return (dom, attr) => dom.currentStyle[attr]; 16 | } else { 17 | return (dom, attr) => getComputedStyle(dom, false)[attr]; 18 | } 19 | })() 20 | 21 | dialogHeaderEl.onmousedown = (e) => { 22 | // 鼠标按下,计算当前元素距离可视区的距离 23 | const disX = e.clientX - dialogHeaderEl.offsetLeft; 24 | const disY = e.clientY - dialogHeaderEl.offsetTop; 25 | 26 | const screenWidth = document.body.clientWidth; // body当前宽度 27 | const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) 28 | 29 | const dragDomWidth = dragDom.offsetWidth; // 对话框宽度 30 | const dragDomheight = dragDom.offsetHeight; // 对话框高度 31 | 32 | const minDragDomLeft = dragDom.offsetLeft; 33 | const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; 34 | 35 | const minDragDomTop = dragDom.offsetTop; 36 | const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; 37 | 38 | 39 | // 获取到的值带px 正则匹配替换 40 | let styL = sty(dragDom, 'left'); 41 | let styT = sty(dragDom, 'top'); 42 | 43 | // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px 44 | if (styL.includes('%')) { 45 | styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100); 46 | styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100); 47 | } else { 48 | styL = +styL.replace(/\px/g, ''); 49 | styT = +styT.replace(/\px/g, ''); 50 | }; 51 | 52 | document.onmousemove = function (e) { 53 | // 通过事件委托,计算移动的距离 54 | let left = e.clientX - disX; 55 | let top = e.clientY - disY; 56 | 57 | // 边界处理 58 | if (-(left) > minDragDomLeft) { 59 | left = -(minDragDomLeft); 60 | } else if (left > maxDragDomLeft) { 61 | left = maxDragDomLeft; 62 | } 63 | 64 | if (-(top) > minDragDomTop) { 65 | top = -(minDragDomTop); 66 | } else if (top > maxDragDomTop) { 67 | top = maxDragDomTop; 68 | } 69 | 70 | // 移动当前元素 71 | dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; 72 | }; 73 | 74 | document.onmouseup = function (e) { 75 | document.onmousemove = null; 76 | document.onmouseup = null; 77 | }; 78 | } 79 | } 80 | }) 81 | -------------------------------------------------------------------------------- /src/assets/js/i18n.js: -------------------------------------------------------------------------------- 1 | export const messages = { 2 | 'zh': { 3 | i18n: { 4 | breadcrumb: '国际化产品', 5 | tips: '通过切换语言按钮,来改变当前内容的语言。', 6 | btn: '切换英文', 7 | title1: '常用用法', 8 | p1: '要是你把你的秘密告诉了风,那就别怪风把它带给树。', 9 | p2: '没有什么比信念更能支撑我们度过艰难的时光了。', 10 | p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。', 11 | title2: '组件插值', 12 | info: 'Element组件需要国际化,请参考 {action}。', 13 | value: '文档' 14 | } 15 | }, 16 | 'en': { 17 | i18n: { 18 | breadcrumb: 'International Products', 19 | tips: 'Click on the button to change the current language. ', 20 | btn: 'Switch Chinese', 21 | title1: 'Common usage', 22 | p1: "If you reveal your secrets to the wind you should not blame the wind for revealing them to the trees.", 23 | p2: "Nothing can help us endure dark times better than our faith. ", 24 | p3: "If you can do what you do best and be happy, you're further along in life than most people.", 25 | title2: 'Component interpolation', 26 | info: 'The default language of Element is Chinese. If you wish to use another language, please refer to the {action}.', 27 | value: 'documentation' 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/assets/js/jquery.countup.min.js: -------------------------------------------------------------------------------- 1 | !function(t){"use strict";t.fn.countUp=function(e){var a=t.extend({time:2e3,delay:10},e);return this.each(function(){var e=t(this),n=a,u=function(){e.data("counterupTo")||e.data("counterupTo",e.text());var t=parseInt(e.data("counter-time"))>0?parseInt(e.data("counter-time")):n.time,a=parseInt(e.data("counter-delay"))>0?parseInt(e.data("counter-delay")):n.delay,u=t/a,r=e.data("counterupTo"),o=[r],c=/[0-9]+,[0-9]+/.test(r);r=r.replace(/,/g,"");for(var d=(/^[0-9]+$/.test(r),/^[0-9]+\.[0-9]+$/.test(r)),s=d?(r.split(".")[1]||[]).length:0,i=u;i>=1;i--){var p=parseInt(Math.round(r/u*i));if(d&&(p=parseFloat(r/u*i).toFixed(s)),c)for(;/(\d+)(\d{3})/.test(p.toString());)p=p.toString().replace(/(\d+)(\d{3})/,"$1,$2");o.unshift(p)}e.data("counterup-nums",o),e.text("0");var f=function(){e.text(e.data("counterup-nums").shift()),e.data("counterup-nums").length?setTimeout(e.data("counterup-func"),a):(delete e.data("counterup-nums"),e.data("counterup-nums",null),e.data("counterup-func",null))};e.data("counterup-func",f),setTimeout(e.data("counterup-func"),a)};e.waypoint(u,{offset:"100%",triggerOnce:!0})})}}(jQuery); -------------------------------------------------------------------------------- /src/assets/js/jquery.waypoints.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.0 3 | Copyright © 2011-2015 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.invokeAll("enable")},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical);t&&e&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s],l=o.oldScroll=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=y+l-f,h=w=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}(); -------------------------------------------------------------------------------- /src/components/Drawer.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 96 | 97 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import ElementUI from 'element-ui'; 5 | import VueI18n from 'vue-i18n'; 6 | import { messages } from './assets/js/i18n'; 7 | import 'element-ui/lib/theme-chalk/index.css'; 8 | import './assets/css/icon.css'; 9 | import './assets/js/directives'; 10 | import 'babel-polyfill' 11 | import VueClipboard from 'vue-clipboard2' 12 | 13 | 14 | let echarts = require('echarts/echarts.all') 15 | Vue.use(VueClipboard) 16 | Vue.config.productionTip = false; 17 | Vue.use(VueI18n); 18 | Vue.use(ElementUI, { 19 | size: 'small' 20 | }); 21 | const i18n = new VueI18n({ 22 | locale: 'zh', 23 | messages 24 | }); 25 | Vue.prototype.$echarts = echarts 26 | 27 | 28 | // 使用钩子函数对路由进行权限跳转 29 | router.beforeEach((to, from, next) => { 30 | // 权限验证 31 | var permission = localStorage.getItem('permission'); 32 | if (to.path == '/login') { 33 | next(); 34 | } else if (!permission && to.path !== '/login') { 35 | next('/login'); 36 | } else if (permission) { 37 | var lock = false; 38 | var per = JSON.parse(permission); 39 | per.forEach(function (item, index) { 40 | if (to.path == '/' + item.alias) { 41 | lock = true; 42 | return false; 43 | } 44 | }) 45 | if (to.path == '/403') { 46 | lock = true; 47 | } 48 | lock == true ? next() : next('/403'); 49 | } else { 50 | // 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容 51 | if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') { 52 | Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', { 53 | confirmButtonText: '确定' 54 | }); 55 | } else { 56 | next(); 57 | } 58 | } 59 | }); 60 | 61 | 62 | new Vue({ 63 | router, 64 | i18n, 65 | render: h => h(App) 66 | }).$mount('#app'); 67 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | 4 | Vue.use(Router); 5 | 6 | export default new Router({ 7 | routes: [ 8 | { 9 | path: '/login', 10 | meta: { title: '登录' }, 11 | component: () => import('../views/common/Login.vue'), 12 | }, 13 | { 14 | path: '/403', 15 | meta: { title: '403' }, 16 | component: () => import('../views/common/403.vue'), 17 | }, 18 | { 19 | path: '/', 20 | redirect: '/login', 21 | component: () => import('../views/common/Home.vue'), 22 | children: [ 23 | { 24 | path: '/dashboard', 25 | meta: { title: '系统首页' }, 26 | component: () => import('../views/common/Dashboard.vue'), 27 | }, 28 | { 29 | path: '/admin', 30 | meta: { title: '管理员' }, 31 | component: () => import('../views/admin/Index.vue'), 32 | }, 33 | { 34 | path: '/role', 35 | meta: { title: '角色管理' }, 36 | component: () => import('../views/role/Index.vue'), 37 | }, 38 | { 39 | path: '/menus', 40 | meta: { title: '菜单管理' }, 41 | component: () => import('../views/menu/Index.vue'), 42 | }, 43 | { 44 | path: '/loginLog', 45 | meta: { title: '登录日志' }, 46 | component: () => import('../views/log/Login.vue'), 47 | }, 48 | { 49 | path: '/requestLog', 50 | meta: { title: '访问日志' }, 51 | component: () => import('../views/log/Request.vue'), 52 | }, 53 | { 54 | path: '/errorLog', 55 | meta: { title: '错误日志' }, 56 | component: () => import('../views/log/Error.vue'), 57 | }, 58 | { 59 | path: '/upload', 60 | meta: { title: '文件上传' }, 61 | component: () => import('../views/component/Upload.vue'), 62 | }, 63 | { 64 | path: '/clipboard', 65 | meta: { title: '复制粘贴' }, 66 | component: () => import('../views/component/Clipboard.vue'), 67 | } 68 | ] 69 | } 70 | ] 71 | }); -------------------------------------------------------------------------------- /src/utils/common.js: -------------------------------------------------------------------------------- 1 | export function json2excel(tableJson, filenames, autowidth, bookTypes) { 2 | import("@/vendor/Export2Excel").then(excel => { 3 | var tHeader = [] 4 | var dataArr = [] 5 | var sheetnames = [] 6 | for (var i in tableJson) { 7 | tHeader.push(tableJson[i].tHeader) 8 | dataArr.push(formatJson(tableJson[i].filterVal, tableJson[i].tableDatas)) 9 | sheetnames.push(tableJson[i].sheetName) 10 | } 11 | excel.export_json_to_excel({ 12 | header: tHeader, 13 | data: dataArr, 14 | sheetname: sheetnames, 15 | filename: filenames, 16 | autoWidth: autowidth, 17 | bookType: bookTypes 18 | }) 19 | }) 20 | } 21 | 22 | // 数据过滤,时间过滤 23 | function formatJson(filterVal, jsonData) { 24 | return jsonData.map(v => 25 | filterVal.map(j => { 26 | if (j === "timestamp") { 27 | return parseTime(v[j]) 28 | } else { 29 | return v[j] 30 | } 31 | }) 32 | ) 33 | } -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import axios from 'axios'; 3 | import router from '../router'; 4 | import { Base64 } from 'js-base64' 5 | import md5 from 'js-md5'; 6 | 7 | const service = axios.create({ 8 | baseURL: 'admin', 9 | timeout: 5000 10 | }); 11 | 12 | // 请求拦截器 13 | service.interceptors.request.use( 14 | config => { 15 | let time = Math.round(new Date() / 1000); 16 | let sign = md5("appname=LaravelAdmin&appsecret=Sl7qkF2DKglAdlk4397qdKCUf3×tamp=" + time); 17 | // 设置请求头 18 | let data = { 19 | sign: sign, 20 | timestamp: time, 21 | token: localStorage.getItem('token') 22 | } 23 | config.headers.token = Base64.encode(JSON.stringify(data)); 24 | return config; 25 | }, 26 | error => { 27 | console.log(error); 28 | return Promise.reject(); 29 | } 30 | ); 31 | 32 | // 响应拦截器 33 | service.interceptors.response.use( 34 | response => { 35 | if (response.status === 200) { 36 | // 拦截登录失效、无权限操作 37 | if (response.data.code === 401) { 38 | localStorage.removeItem('token'); 39 | localStorage.removeItem('username'); 40 | localStorage.removeItem('error_count'); 41 | localStorage.removeItem('permission'); 42 | Vue.prototype.$alert(response.data.msg, { 43 | confirmButtonText: '确定', 44 | showClose: false, 45 | callback: action => { 46 | router.push('/login'); 47 | } 48 | }); 49 | } 50 | return response.data; 51 | } else { 52 | Promise.reject(); 53 | } 54 | }, 55 | error => { 56 | console.log(error); 57 | return Promise.reject(); 58 | } 59 | ); 60 | 61 | export default service; -------------------------------------------------------------------------------- /src/vendor/Blob.js: -------------------------------------------------------------------------------- 1 | /* Blob.js 2 | * A Blob, File, FileReader & URL implementation. 3 | * 2019-04-19 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * By Jimmy Wärting, https://github.com/jimmywarting 7 | * License: MIT 8 | * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md 9 | */ 10 | 11 | ;(function () { 12 | var global = 13 | typeof window === "object" ? window : typeof self === "object" ? self : this 14 | 15 | var BlobBuilder = 16 | global.BlobBuilder || 17 | global.WebKitBlobBuilder || 18 | global.MSBlobBuilder || 19 | global.MozBlobBuilder 20 | global.URL = 21 | global.URL || 22 | global.webkitURL || 23 | function (href, a) { 24 | a = document.createElement("a") 25 | a.href = href 26 | return a 27 | } 28 | var origBlob = global.Blob 29 | var createObjectURL = URL.createObjectURL 30 | var revokeObjectURL = URL.revokeObjectURL 31 | var strTag = global.Symbol && global.Symbol.toStringTag 32 | var blobSupported = false 33 | var blobSupportsArrayBufferView = false 34 | var arrayBufferSupported = !!global.ArrayBuffer 35 | var blobBuilderSupported = 36 | BlobBuilder && BlobBuilder.prototype.append && BlobBuilder.prototype.getBlob 37 | 38 | try { 39 | // Check if Blob constructor is supported 40 | blobSupported = new Blob(["ä"]).size === 2 41 | // Check if Blob constructor supports ArrayBufferViews 42 | // Fails in Safari 6, so we need to map to ArrayBuffers there. 43 | blobSupportsArrayBufferView = new Blob([new Uint8Array([1, 2])]).size === 2 44 | } catch (e) {} 45 | /** 46 | * Helper function that maps ArrayBufferViews to ArrayBuffers 47 | * Used by BlobBuilder constructor and old browsers that didn't 48 | * support it in the Blob constructor. 49 | */ 50 | function mapArrayBufferViews (ary) { 51 | return ary.map(function (chunk) { 52 | if (chunk.buffer instanceof ArrayBuffer) { 53 | var buf = chunk.buffer 54 | 55 | // if this is a subarray, make a copy so we only 56 | // include the subarray region from the underlying buffer 57 | if (chunk.byteLength !== buf.byteLength) { 58 | var copy = new Uint8Array(chunk.byteLength) 59 | copy.set(new Uint8Array(buf, chunk.byteOffset, chunk.byteLength)) 60 | buf = copy.buffer 61 | } 62 | 63 | return buf 64 | } 65 | 66 | return chunk 67 | }) 68 | } 69 | 70 | function BlobBuilderConstructor (ary, options) { 71 | options = options || {} 72 | 73 | var bb = new BlobBuilder() 74 | mapArrayBufferViews(ary).forEach(function (part) { 75 | bb.append(part) 76 | }) 77 | 78 | return options.type ? bb.getBlob(options.type) : bb.getBlob() 79 | } 80 | 81 | function BlobConstructor (ary, options) { 82 | return new origBlob(mapArrayBufferViews(ary), options || {}) 83 | } 84 | 85 | if (global.Blob) { 86 | BlobBuilderConstructor.prototype = Blob.prototype 87 | BlobConstructor.prototype = Blob.prototype 88 | } 89 | 90 | /********************************************************/ 91 | /* String Encoder fallback */ 92 | /********************************************************/ 93 | function stringEncode (string) { 94 | var pos = 0 95 | var len = string.length 96 | var out = [] 97 | var Arr = global.Uint8Array || Array // Use byte array when possible 98 | 99 | var at = 0 // output position 100 | var tlen = Math.max(32, len + (len >> 1) + 7) // 1.5x size 101 | var target = new Arr((tlen >> 3) << 3) // ... but at 8 byte offset 102 | 103 | while (pos < len) { 104 | var value = string.charCodeAt(pos++) 105 | if (value >= 0xd800 && value <= 0xdbff) { 106 | // high surrogate 107 | if (pos < len) { 108 | var extra = string.charCodeAt(pos) 109 | if ((extra & 0xfc00) === 0xdc00) { 110 | ++pos 111 | value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000 112 | } 113 | } 114 | if (value >= 0xd800 && value <= 0xdbff) { 115 | continue // drop lone surrogate 116 | } 117 | } 118 | 119 | // expand the buffer if we couldn't write 4 bytes 120 | if (at + 4 > target.length) { 121 | tlen += 8 // minimum extra 122 | tlen *= 1.0 + (pos / string.length) * 2 // take 2x the remaining 123 | tlen = (tlen >> 3) << 3 // 8 byte offset 124 | 125 | const update = new Uint8Array(tlen) 126 | update.set(target) 127 | target = update 128 | } 129 | 130 | if ((value & 0xffffff80) === 0) { 131 | // 1-byte 132 | target[at++] = value // ASCII 133 | continue 134 | } else if ((value & 0xfffff800) === 0) { 135 | // 2-byte 136 | target[at++] = ((value >> 6) & 0x1f) | 0xc0 137 | } else if ((value & 0xffff0000) === 0) { 138 | // 3-byte 139 | target[at++] = ((value >> 12) & 0x0f) | 0xe0 140 | target[at++] = ((value >> 6) & 0x3f) | 0x80 141 | } else if ((value & 0xffe00000) === 0) { 142 | // 4-byte 143 | target[at++] = ((value >> 18) & 0x07) | 0xf0 144 | target[at++] = ((value >> 12) & 0x3f) | 0x80 145 | target[at++] = ((value >> 6) & 0x3f) | 0x80 146 | } else { 147 | // FIXME: do we care 148 | continue 149 | } 150 | 151 | target[at++] = (value & 0x3f) | 0x80 152 | } 153 | 154 | return target.slice(0, at) 155 | } 156 | 157 | /********************************************************/ 158 | /* String Decoder fallback */ 159 | /********************************************************/ 160 | function stringDecode (buf) { 161 | var end = buf.length 162 | var res = [] 163 | 164 | var i = 0 165 | while (i < end) { 166 | var firstByte = buf[i] 167 | var codePoint = null 168 | var bytesPerSequence = 169 | firstByte > 0xef ? 4 : firstByte > 0xdf ? 3 : firstByte > 0xbf ? 2 : 1 170 | 171 | if (i + bytesPerSequence <= end) { 172 | var secondByte, thirdByte, fourthByte, tempCodePoint 173 | 174 | switch (bytesPerSequence) { 175 | case 1: 176 | if (firstByte < 0x80) { 177 | codePoint = firstByte 178 | } 179 | break 180 | case 2: 181 | secondByte = buf[i + 1] 182 | if ((secondByte & 0xc0) === 0x80) { 183 | tempCodePoint = ((firstByte & 0x1f) << 0x6) | (secondByte & 0x3f) 184 | if (tempCodePoint > 0x7f) { 185 | codePoint = tempCodePoint 186 | } 187 | } 188 | break 189 | case 3: 190 | secondByte = buf[i + 1] 191 | thirdByte = buf[i + 2] 192 | if ((secondByte & 0xc0) === 0x80 && (thirdByte & 0xc0) === 0x80) { 193 | tempCodePoint = 194 | ((firstByte & 0xf) << 0xc) | 195 | ((secondByte & 0x3f) << 0x6) | 196 | (thirdByte & 0x3f) 197 | if ( 198 | tempCodePoint > 0x7ff && 199 | (tempCodePoint < 0xd800 || tempCodePoint > 0xdfff) 200 | ) { 201 | codePoint = tempCodePoint 202 | } 203 | } 204 | break 205 | case 4: 206 | secondByte = buf[i + 1] 207 | thirdByte = buf[i + 2] 208 | fourthByte = buf[i + 3] 209 | if ( 210 | (secondByte & 0xc0) === 0x80 && 211 | (thirdByte & 0xc0) === 0x80 && 212 | (fourthByte & 0xc0) === 0x80 213 | ) { 214 | tempCodePoint = 215 | ((firstByte & 0xf) << 0x12) | 216 | ((secondByte & 0x3f) << 0xc) | 217 | ((thirdByte & 0x3f) << 0x6) | 218 | (fourthByte & 0x3f) 219 | if (tempCodePoint > 0xffff && tempCodePoint < 0x110000) { 220 | codePoint = tempCodePoint 221 | } 222 | } 223 | } 224 | } 225 | 226 | if (codePoint === null) { 227 | // we did not generate a valid codePoint so insert a 228 | // replacement char (U+FFFD) and advance only 1 byte 229 | codePoint = 0xfffd 230 | bytesPerSequence = 1 231 | } else if (codePoint > 0xffff) { 232 | // encode to utf16 (surrogate pair dance) 233 | codePoint -= 0x10000 234 | res.push(((codePoint >>> 10) & 0x3ff) | 0xd800) 235 | codePoint = 0xdc00 | (codePoint & 0x3ff) 236 | } 237 | 238 | res.push(codePoint) 239 | i += bytesPerSequence 240 | } 241 | 242 | var len = res.length 243 | var str = "" 244 | var i = 0 245 | 246 | while (i < len) { 247 | str += String.fromCharCode.apply(String, res.slice(i, (i += 0x1000))) 248 | } 249 | 250 | return str 251 | } 252 | 253 | // string -> buffer 254 | var textEncode = 255 | typeof TextEncoder === "function" 256 | ? TextEncoder.prototype.encode.bind(new TextEncoder()) 257 | : stringEncode 258 | 259 | // buffer -> string 260 | var textDecode = 261 | typeof TextDecoder === "function" 262 | ? TextDecoder.prototype.decode.bind(new TextDecoder()) 263 | : stringDecode 264 | 265 | function FakeBlobBuilder () { 266 | function isDataView (obj) { 267 | return obj && DataView.prototype.isPrototypeOf(obj) 268 | } 269 | function bufferClone (buf) { 270 | var view = new Array(buf.byteLength) 271 | var array = new Uint8Array(buf) 272 | var i = view.length 273 | while (i--) { 274 | view[i] = array[i] 275 | } 276 | return view 277 | } 278 | function array2base64 (input) { 279 | var byteToCharMap = 280 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" 281 | 282 | var output = [] 283 | 284 | for (var i = 0; i < input.length; i += 3) { 285 | var byte1 = input[i] 286 | var haveByte2 = i + 1 < input.length 287 | var byte2 = haveByte2 ? input[i + 1] : 0 288 | var haveByte3 = i + 2 < input.length 289 | var byte3 = haveByte3 ? input[i + 2] : 0 290 | 291 | var outByte1 = byte1 >> 2 292 | var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4) 293 | var outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6) 294 | var outByte4 = byte3 & 0x3f 295 | 296 | if (!haveByte3) { 297 | outByte4 = 64 298 | 299 | if (!haveByte2) { 300 | outByte3 = 64 301 | } 302 | } 303 | 304 | output.push( 305 | byteToCharMap[outByte1], 306 | byteToCharMap[outByte2], 307 | byteToCharMap[outByte3], 308 | byteToCharMap[outByte4] 309 | ) 310 | } 311 | 312 | return output.join("") 313 | } 314 | 315 | var create = 316 | Object.create || 317 | function (a) { 318 | function c () {} 319 | c.prototype = a 320 | return new c() 321 | } 322 | 323 | if (arrayBufferSupported) { 324 | var viewClasses = [ 325 | "[object Int8Array]", 326 | "[object Uint8Array]", 327 | "[object Uint8ClampedArray]", 328 | "[object Int16Array]", 329 | "[object Uint16Array]", 330 | "[object Int32Array]", 331 | "[object Uint32Array]", 332 | "[object Float32Array]", 333 | "[object Float64Array]" 334 | ] 335 | 336 | var isArrayBufferView = 337 | ArrayBuffer.isView || 338 | function (obj) { 339 | return ( 340 | obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1 341 | ) 342 | } 343 | } 344 | 345 | function concatTypedarrays (chunks) { 346 | var size = 0 347 | var i = chunks.length 348 | while (i--) { 349 | size += chunks[i].length 350 | } 351 | var b = new Uint8Array(size) 352 | var offset = 0 353 | for (i = 0, l = chunks.length; i < l; i++) { 354 | var chunk = chunks[i] 355 | b.set(chunk, offset) 356 | offset += chunk.byteLength || chunk.length 357 | } 358 | 359 | return b 360 | } 361 | 362 | /********************************************************/ 363 | /* Blob constructor */ 364 | /********************************************************/ 365 | function Blob (chunks, opts) { 366 | chunks = chunks || [] 367 | opts = opts == null ? {} : opts 368 | for (var i = 0, len = chunks.length; i < len; i++) { 369 | var chunk = chunks[i] 370 | if (chunk instanceof Blob) { 371 | chunks[i] = chunk._buffer 372 | } else if (typeof chunk === "string") { 373 | chunks[i] = textEncode(chunk) 374 | } else if ( 375 | arrayBufferSupported && 376 | (ArrayBuffer.prototype.isPrototypeOf(chunk) || 377 | isArrayBufferView(chunk)) 378 | ) { 379 | chunks[i] = bufferClone(chunk) 380 | } else if (arrayBufferSupported && isDataView(chunk)) { 381 | chunks[i] = bufferClone(chunk.buffer) 382 | } else { 383 | chunks[i] = textEncode(String(chunk)) 384 | } 385 | } 386 | 387 | this._buffer = global.Uint8Array 388 | ? concatTypedarrays(chunks) 389 | : [].concat.apply([], chunks) 390 | this.size = this._buffer.length 391 | 392 | this.type = opts.type || "" 393 | if (/[^\u0020-\u007E]/.test(this.type)) { 394 | this.type = "" 395 | } else { 396 | this.type = this.type.toLowerCase() 397 | } 398 | } 399 | 400 | Blob.prototype.arrayBuffer = function () { 401 | return Promise.resolve(this._buffer) 402 | } 403 | 404 | Blob.prototype.text = function () { 405 | return Promise.resolve(textDecode(this._buffer)) 406 | } 407 | 408 | Blob.prototype.slice = function (start, end, type) { 409 | var slice = this._buffer.slice(start || 0, end || this._buffer.length) 410 | return new Blob([slice], { type: type }) 411 | } 412 | 413 | Blob.prototype.toString = function () { 414 | return "[object Blob]" 415 | } 416 | 417 | /********************************************************/ 418 | /* File constructor */ 419 | /********************************************************/ 420 | function File (chunks, name, opts) { 421 | opts = opts || {} 422 | var a = Blob.call(this, chunks, opts) || this 423 | a.name = name.replace(/\//g, ":") 424 | a.lastModifiedDate = opts.lastModified 425 | ? new Date(opts.lastModified) 426 | : new Date() 427 | a.lastModified = +a.lastModifiedDate 428 | 429 | return a 430 | } 431 | 432 | File.prototype = create(Blob.prototype) 433 | File.prototype.constructor = File 434 | 435 | if (Object.setPrototypeOf) { 436 | Object.setPrototypeOf(File, Blob) 437 | } else { 438 | try { 439 | File.__proto__ = Blob 440 | } catch (e) {} 441 | } 442 | 443 | File.prototype.toString = function () { 444 | return "[object File]" 445 | } 446 | 447 | /********************************************************/ 448 | /* FileReader constructor */ 449 | /********************************************************/ 450 | function FileReader () { 451 | if (!(this instanceof FileReader)) { 452 | throw new TypeError( 453 | "Failed to construct 'FileReader': Please use the 'new' operator, this DOM object constructor cannot be called as a function." 454 | ) 455 | } 456 | 457 | var delegate = document.createDocumentFragment() 458 | this.addEventListener = delegate.addEventListener 459 | this.dispatchEvent = function (evt) { 460 | var local = this["on" + evt.type] 461 | if (typeof local === "function") local(evt) 462 | delegate.dispatchEvent(evt) 463 | } 464 | this.removeEventListener = delegate.removeEventListener 465 | } 466 | 467 | function _read (fr, blob, kind) { 468 | if (!(blob instanceof Blob)) { 469 | throw new TypeError( 470 | "Failed to execute '" + 471 | kind + 472 | "' on 'FileReader': parameter 1 is not of type 'Blob'." 473 | ) 474 | } 475 | 476 | fr.result = "" 477 | 478 | setTimeout(function () { 479 | this.readyState = FileReader.LOADING 480 | fr.dispatchEvent(new Event("load")) 481 | fr.dispatchEvent(new Event("loadend")) 482 | }) 483 | } 484 | 485 | FileReader.EMPTY = 0 486 | FileReader.LOADING = 1 487 | FileReader.DONE = 2 488 | FileReader.prototype.error = null 489 | FileReader.prototype.onabort = null 490 | FileReader.prototype.onerror = null 491 | FileReader.prototype.onload = null 492 | FileReader.prototype.onloadend = null 493 | FileReader.prototype.onloadstart = null 494 | FileReader.prototype.onprogress = null 495 | 496 | FileReader.prototype.readAsDataURL = function (blob) { 497 | _read(this, blob, "readAsDataURL") 498 | this.result = 499 | "data:" + blob.type + ";base64," + array2base64(blob._buffer) 500 | } 501 | 502 | FileReader.prototype.readAsText = function (blob) { 503 | _read(this, blob, "readAsText") 504 | this.result = textDecode(blob._buffer) 505 | } 506 | 507 | FileReader.prototype.readAsArrayBuffer = function (blob) { 508 | _read(this, blob, "readAsText") 509 | // return ArrayBuffer when possible 510 | this.result = (blob._buffer.buffer || blob._buffer).slice() 511 | } 512 | 513 | FileReader.prototype.abort = function () {} 514 | 515 | /********************************************************/ 516 | /* URL */ 517 | /********************************************************/ 518 | URL.createObjectURL = function (blob) { 519 | return blob instanceof Blob 520 | ? "data:" + blob.type + ";base64," + array2base64(blob._buffer) 521 | : createObjectURL.call(URL, blob) 522 | } 523 | 524 | URL.revokeObjectURL = function (url) { 525 | revokeObjectURL && revokeObjectURL.call(URL, url) 526 | } 527 | 528 | /********************************************************/ 529 | /* XHR */ 530 | /********************************************************/ 531 | var _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send 532 | if (_send) { 533 | XMLHttpRequest.prototype.send = function (data) { 534 | if (data instanceof Blob) { 535 | this.setRequestHeader("Content-Type", data.type) 536 | _send.call(this, textDecode(data._buffer)) 537 | } else { 538 | _send.call(this, data) 539 | } 540 | } 541 | } 542 | 543 | global.FileReader = FileReader 544 | global.File = File 545 | global.Blob = Blob 546 | } 547 | 548 | function fixFileAndXHR () { 549 | var isIE = 550 | !!global.ActiveXObject || 551 | ("-ms-scroll-limit" in document.documentElement.style && 552 | "-ms-ime-align" in document.documentElement.style) 553 | 554 | // Monkey patched 555 | // IE don't set Content-Type header on XHR whose body is a typed Blob 556 | // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6047383 557 | var _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send 558 | if (isIE && _send) { 559 | XMLHttpRequest.prototype.send = function (data) { 560 | if (data instanceof Blob) { 561 | this.setRequestHeader("Content-Type", data.type) 562 | _send.call(this, data) 563 | } else { 564 | _send.call(this, data) 565 | } 566 | } 567 | } 568 | 569 | try { 570 | new File([], "") 571 | } catch (e) { 572 | try { 573 | var klass = new Function( 574 | "class File extends Blob {" + 575 | "constructor(chunks, name, opts) {" + 576 | "opts = opts || {};" + 577 | "super(chunks, opts || {});" + 578 | "this.name = name.replace(///g, \":\");" + 579 | "this.lastModifiedDate = opts.lastModified ? new Date(opts.lastModified) : new Date();" + 580 | "this.lastModified = +this.lastModifiedDate;" + 581 | "}};" + 582 | "return new File([], \"\"), File" 583 | )() 584 | global.File = klass 585 | } catch (e) { 586 | var klass = function (b, d, c) { 587 | var blob = new Blob(b, c) 588 | var t = 589 | c && void 0 !== c.lastModified 590 | ? new Date(c.lastModified) 591 | : new Date() 592 | 593 | blob.name = d.replace(/\//g, ":") 594 | blob.lastModifiedDate = t 595 | blob.lastModified = +t 596 | blob.toString = function () { 597 | return "[object File]" 598 | } 599 | 600 | if (strTag) { 601 | blob[strTag] = "File" 602 | } 603 | 604 | return blob 605 | } 606 | global.File = klass 607 | } 608 | } 609 | } 610 | 611 | if (blobSupported) { 612 | fixFileAndXHR() 613 | global.Blob = blobSupportsArrayBufferView ? global.Blob : BlobConstructor 614 | } else if (blobBuilderSupported) { 615 | fixFileAndXHR() 616 | global.Blob = BlobBuilderConstructor 617 | } else { 618 | FakeBlobBuilder() 619 | } 620 | 621 | if (strTag) { 622 | File.prototype[strTag] = "File" 623 | Blob.prototype[strTag] = "Blob" 624 | FileReader.prototype[strTag] = "FileReader" 625 | } 626 | 627 | var blob = global.Blob.prototype 628 | var stream 629 | 630 | function promisify (obj) { 631 | return new Promise(function (resolve, reject) { 632 | obj.onload = obj.onerror = function (evt) { 633 | obj.onload = obj.onerror = null 634 | 635 | evt.type === "load" 636 | ? resolve(obj.result || obj) 637 | : reject(new Error("Failed to read the blob/file")) 638 | } 639 | }) 640 | } 641 | 642 | try { 643 | new ReadableStream({ type: "bytes" }) 644 | stream = function stream () { 645 | var position = 0 646 | var blob = this 647 | 648 | return new ReadableStream({ 649 | type: "bytes", 650 | autoAllocateChunkSize: 524288, 651 | 652 | pull: function (controller) { 653 | var v = controller.byobRequest.view 654 | var chunk = blob.slice(position, position + v.byteLength) 655 | return chunk.arrayBuffer().then(function (buffer) { 656 | var uint8array = new Uint8Array(buffer) 657 | var bytesRead = uint8array.byteLength 658 | 659 | position += bytesRead 660 | v.set(uint8array) 661 | controller.byobRequest.respond(bytesRead) 662 | 663 | if (position >= blob.size) controller.close() 664 | }) 665 | } 666 | }) 667 | } 668 | } catch (e) { 669 | try { 670 | new ReadableStream({}) 671 | stream = function stream (blob) { 672 | var position = 0 673 | var blob = this 674 | 675 | return new ReadableStream({ 676 | pull: function (controller) { 677 | var chunk = blob.slice(position, position + 524288) 678 | 679 | return chunk.arrayBuffer().then(function (buffer) { 680 | position += buffer.byteLength 681 | var uint8array = new Uint8Array(buffer) 682 | controller.enqueue(uint8array) 683 | 684 | if (position == blob.size) controller.close() 685 | }) 686 | } 687 | }) 688 | } 689 | } catch (e) { 690 | try { 691 | new Response("").body.getReader().read() 692 | stream = function stream () { 693 | return new Response(this).body 694 | } 695 | } catch (e) { 696 | stream = function stream () { 697 | throw new Error( 698 | "Include https://github.com/MattiasBuelens/web-streams-polyfill" 699 | ) 700 | } 701 | } 702 | } 703 | } 704 | 705 | if (!blob.arrayBuffer) { 706 | blob.arrayBuffer = function arrayBuffer () { 707 | var fr = new FileReader() 708 | fr.readAsArrayBuffer(this) 709 | return promisify(fr) 710 | } 711 | } 712 | 713 | if (!blob.text) { 714 | blob.text = function text () { 715 | var fr = new FileReader() 716 | fr.readAsText(this) 717 | return promisify(fr) 718 | } 719 | } 720 | 721 | if (!blob.stream) { 722 | blob.stream = stream 723 | } 724 | })() 725 | -------------------------------------------------------------------------------- /src/vendor/Export2Excel.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require("script-loader!file-saver") 3 | import XLSX from "xlsx" 4 | 5 | function generateArray(table) { 6 | var out = [] 7 | var rows = table.querySelectorAll("tr") 8 | var ranges = [] 9 | for (var R = 0; R < rows.length; ++R) { 10 | var outRow = [] 11 | var row = rows[R] 12 | var columns = row.querySelectorAll("td") 13 | for (var C = 0; C < columns.length; ++C) { 14 | var cell = columns[C] 15 | var colspan = cell.getAttribute("colspan") 16 | var rowspan = cell.getAttribute("rowspan") 17 | var cellValue = cell.innerText 18 | if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue 19 | //Skip ranges 20 | ranges.forEach(function (range) { 21 | if ( 22 | R >= range.s.r && 23 | R <= range.e.r && 24 | outRow.length >= range.s.c && 25 | outRow.length <= range.e.c 26 | ) { 27 | for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null) 28 | } 29 | }) 30 | 31 | //Handle Row Span 32 | if (rowspan || colspan) { 33 | rowspan = rowspan || 1 34 | colspan = colspan || 1 35 | ranges.push({ 36 | s: { 37 | r: R, 38 | c: outRow.length 39 | }, 40 | e: { 41 | r: R + rowspan - 1, 42 | c: outRow.length + colspan - 1 43 | } 44 | }) 45 | } 46 | 47 | //Handle Value 48 | outRow.push(cellValue !== "" ? cellValue : null) 49 | 50 | //Handle Colspan 51 | if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null) 52 | } 53 | out.push(outRow) 54 | } 55 | return [out, ranges] 56 | } 57 | 58 | function datenum(v, date1904) { 59 | if (date1904) v += 1462 60 | var epoch = Date.parse(v) 61 | return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000) 62 | } 63 | 64 | function sheet_from_array_of_arrays(data, opts) { 65 | var ws = {} 66 | var range = { 67 | s: { 68 | c: 10000000, 69 | r: 10000000 70 | }, 71 | e: { 72 | c: 0, 73 | r: 0 74 | } 75 | } 76 | for (var R = 0; R != data.length; ++R) { 77 | for (var C = 0; C != data[R].length; ++C) { 78 | if (range.s.r > R) range.s.r = R 79 | if (range.s.c > C) range.s.c = C 80 | if (range.e.r < R) range.e.r = R 81 | if (range.e.c < C) range.e.c = C 82 | var cell = { 83 | v: data[R][C] 84 | } 85 | if (cell.v == null) continue 86 | var cell_ref = XLSX.utils.encode_cell({ 87 | c: C, 88 | r: R 89 | }) 90 | 91 | if (typeof cell.v === "number") cell.t = "n" 92 | else if (typeof cell.v === "boolean") cell.t = "b" 93 | else if (cell.v instanceof Date) { 94 | cell.t = "n" 95 | cell.z = XLSX.SSF._table[14] 96 | cell.v = datenum(cell.v) 97 | } else cell.t = "s" 98 | 99 | ws[cell_ref] = cell 100 | } 101 | } 102 | if (range.s.c < 10000000) ws["!ref"] = XLSX.utils.encode_range(range) 103 | return ws 104 | } 105 | 106 | function Workbook() { 107 | if (!(this instanceof Workbook)) return new Workbook() 108 | this.SheetNames = [] 109 | this.Sheets = {} 110 | } 111 | 112 | function s2ab(s) { 113 | var buf = new ArrayBuffer(s.length) 114 | var view = new Uint8Array(buf) 115 | for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff 116 | return buf 117 | } 118 | 119 | export function export_table_to_excel(id) { 120 | var theTable = document.getElementById(id) 121 | var oo = generateArray(theTable) 122 | var ranges = oo[1] 123 | 124 | /* original data */ 125 | var data = oo[0] 126 | var ws_name = "SheetJS" 127 | 128 | var wb = new Workbook(), 129 | ws = sheet_from_array_of_arrays(data) 130 | 131 | /* add ranges to worksheet */ 132 | // ws['!cols'] = ['apple', 'banan']; 133 | ws["!merges"] = ranges 134 | 135 | /* add worksheet to workbook */ 136 | wb.SheetNames.push(ws_name) 137 | wb.Sheets[ws_name] = ws 138 | 139 | var wbout = XLSX.write(wb, { 140 | bookType: "xlsx", 141 | bookSST: false, 142 | type: "binary" 143 | }) 144 | 145 | saveAs( 146 | new Blob([s2ab(wbout)], { 147 | type: "application/octet-stream" 148 | }), 149 | "test.xlsx" 150 | ) 151 | } 152 | 153 | export function export_json_to_excel({ 154 | multiHeader = [], 155 | header, 156 | data, 157 | sheetname, 158 | filename, 159 | merges = [], 160 | autoWidth = true, 161 | bookType = "xlsx" 162 | } = {}) { 163 | /* original data */ 164 | filename = filename || "excel-list" 165 | data = [...data] 166 | 167 | for (var i = 0; i < header.length; i++) { 168 | data[i].unshift(header[i]) 169 | } 170 | 171 | // data.unshift(header) 172 | 173 | for (let i = multiHeader.length - 1; i > -1; i--) { 174 | data.unshift(multiHeader[i]) 175 | } 176 | 177 | var ws_name = sheetname 178 | var wb = new Workbook(), 179 | ws = [] 180 | for (var j = 0; j < header.length; j++) { 181 | ws.push(sheet_from_array_of_arrays(data[j])) 182 | } 183 | 184 | if (merges.length > 0) { 185 | if (!ws["!merges"]) ws["!merges"] = [] 186 | merges.forEach(item => { 187 | ws["!merges"].push(XLSX.utils.decode_range(item)) 188 | }) 189 | } 190 | // console.log("width", autoWidth) 191 | if (autoWidth) { 192 | /*设置worksheet每列的最大宽度*/ 193 | var colWidth = [] 194 | for (var k = 0; k < header.length; k++) { 195 | colWidth.push( 196 | data[k].map(row => 197 | row.map(val => { 198 | /*先判断是否为null/undefined*/ 199 | if (val == null) { 200 | return { 201 | wch: 10 202 | } 203 | } else if (val.toString().charCodeAt(0) > 255) { 204 | /*再判断是否为中文*/ 205 | return { 206 | wch: val.toString().length * 2 207 | } 208 | } else { 209 | return { 210 | wch: val.toString().length 211 | } 212 | } 213 | }) 214 | ) 215 | ) 216 | } 217 | 218 | /*以第一行为初始值*/ 219 | let result = [] 220 | for (var k = 0; k < colWidth.length; k++) { 221 | result[k] = colWidth[k][0] 222 | for (let i = 1; i < colWidth[k].length; i++) { 223 | for (let j = 0; j < colWidth[k][i].length; j++) { 224 | if (result[k][j]["wch"] < colWidth[k][i][j]["wch"]) { 225 | result[k][j]["wch"] = colWidth[k][i][j]["wch"] 226 | } 227 | } 228 | } 229 | } 230 | // 分别给sheet表设置宽度 231 | for (var l = 0; l < result.length; l++) { 232 | ws[l]["!cols"] = result[l] 233 | } 234 | } 235 | 236 | /* add worksheet to workbook */ 237 | for (var k = 0; k < header.length; k++) { 238 | wb.SheetNames.push(ws_name[k]) 239 | wb.Sheets[ws_name[k]] = ws[k] 240 | } 241 | 242 | var wbout = XLSX.write(wb, { 243 | bookType: bookType, 244 | bookSST: false, 245 | type: "binary" 246 | }) 247 | saveAs( 248 | new Blob([s2ab(wbout)], { 249 | type: "application/octet-stream" 250 | }), 251 | `${filename}.${bookType}` 252 | ) 253 | } 254 | -------------------------------------------------------------------------------- /src/views/admin/Create.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 100 | 101 | -------------------------------------------------------------------------------- /src/views/admin/Edit.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 97 | 98 | -------------------------------------------------------------------------------- /src/views/admin/Index.vue: -------------------------------------------------------------------------------- 1 | 77 | 78 | 214 | 215 | -------------------------------------------------------------------------------- /src/views/common/403.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | 50 | -------------------------------------------------------------------------------- /src/views/common/ChangePassword.vue: -------------------------------------------------------------------------------- 1 | 19 | 59 | -------------------------------------------------------------------------------- /src/views/common/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 496 | 497 | -------------------------------------------------------------------------------- /src/views/common/Header.vue: -------------------------------------------------------------------------------- 1 | 48 | 133 | -------------------------------------------------------------------------------- /src/views/common/Home.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 53 | -------------------------------------------------------------------------------- /src/views/common/Login.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 83 | 84 | -------------------------------------------------------------------------------- /src/views/common/Sidebar.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 90 | 91 | -------------------------------------------------------------------------------- /src/views/common/Tags.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 115 | 116 | 117 | 188 | -------------------------------------------------------------------------------- /src/views/component/Clipboard.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 36 | 37 | -------------------------------------------------------------------------------- /src/views/component/Upload.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 178 | 179 | -------------------------------------------------------------------------------- /src/views/log/Error.vue: -------------------------------------------------------------------------------- 1 | 76 | 77 | 161 | 162 | -------------------------------------------------------------------------------- /src/views/log/Login.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 90 | 91 | 121 | -------------------------------------------------------------------------------- /src/views/log/Request.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 58 | 59 | 89 | -------------------------------------------------------------------------------- /src/views/menu/Create.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 99 | 100 | -------------------------------------------------------------------------------- /src/views/menu/Edit.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 107 | 108 | -------------------------------------------------------------------------------- /src/views/menu/Index.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 155 | 156 | -------------------------------------------------------------------------------- /src/views/role/Create.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 95 | 96 | -------------------------------------------------------------------------------- /src/views/role/Edit.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 123 | 124 | -------------------------------------------------------------------------------- /src/views/role/Index.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 158 | 159 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: './', 3 | assetsDir: 'static', 4 | productionSourceMap: false, 5 | devServer: { 6 | // 设置代理 7 | proxy: { 8 | '/admin': { 9 | target: 'http://local.laravelAdmin.com', 10 | changeOrigin: true, 11 | pathRewrite: { 12 | '^/': '' 13 | } 14 | } 15 | } 16 | } 17 | } --------------------------------------------------------------------------------