From 0bf61aac535b7799a0f17573741fee507003a7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com> Date: Wed, 10 Jun 2020 21:47:50 +0800 Subject: [PATCH 01/10] chore: turn on the preload --- vue.config.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vue.config.js b/vue.config.js index ba5be418..aabbf651 100644 --- a/vue.config.js +++ b/vue.config.js @@ -49,8 +49,11 @@ module.exports = { } }, chainWebpack(config) { - config.plugins.delete('preload') // TODO: need test - config.plugins.delete('prefetch') // TODO: need test + // it can improve the speed of the first screen, it is recommended to turn on preload + // config.plugins.delete('preload') + + // when there are many pages, it will cause too many meaningless requests + config.plugins.delete('prefetch') // // set svg-sprite-loader config.module From d3bd933a8e314e5e51d48125dbcda9e3df8ee673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com> Date: Thu, 11 Jun 2020 11:40:53 +0800 Subject: [PATCH 02/10] refactor: change mock files to commonjs (#3246) --- mock/article.js | 4 ++-- mock/index.js | 19 ++++++++++-------- mock/mock-server.js | 5 +---- mock/remote-search.js | 4 ++-- mock/role/index.js | 8 ++++---- mock/role/routes.js | 9 +++++++-- mock/user.js | 2 +- mock/utils.js | 46 +++++++++++++++++++++++++++++++++++++++++++ package.json | 2 -- 9 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 mock/utils.js diff --git a/mock/article.js b/mock/article.js index 50218ae4..23d8ba51 100644 --- a/mock/article.js +++ b/mock/article.js @@ -1,4 +1,4 @@ -import Mock from 'mockjs' +const Mock = require('mockjs') const List = [] const count = 100 @@ -27,7 +27,7 @@ for (let i = 0; i < count; i++) { })) } -export default [ +module.exports = [ { url: '/vue-element-admin/article/list', type: 'get', diff --git a/mock/index.js b/mock/index.js index 196e2927..2eed65db 100644 --- a/mock/index.js +++ b/mock/index.js @@ -1,10 +1,10 @@ -import Mock from 'mockjs' -import { param2Obj } from '../src/utils' +const Mock = require('mockjs') +const { param2Obj } = require('./utils') -import user from './user' -import role from './role' -import article from './article' -import search from './remote-search' +const user = require('./user') +const role = require('./role') +const article = require('./article') +const search = require('./remote-search') const mocks = [ ...user, @@ -16,7 +16,7 @@ const mocks = [ // for front mock // please use it cautiously, it will redefine XMLHttpRequest, // which will cause many of your third-party libraries to be invalidated(like progress event). -export function mockXHR() { +function mockXHR() { // mock patch // https://github.com/nuysoft/Mock/issues/300 Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send @@ -54,4 +54,7 @@ export function mockXHR() { } } -export default mocks +module.exports = { + mocks, + mockXHR +} diff --git a/mock/mock-server.js b/mock/mock-server.js index 806fdacc..8941ec0f 100644 --- a/mock/mock-server.js +++ b/mock/mock-server.js @@ -8,7 +8,7 @@ const mockDir = path.join(process.cwd(), 'mock') function registerRoutes(app) { let mockLastIndex - const { default: mocks } = require('./index.js') + const { mocks } = require('./index.js') const mocksForServer = mocks.map(route => { return responseFake(route.url, route.type, route.response) }) @@ -44,9 +44,6 @@ const responseFake = (url, type, respond) => { } module.exports = app => { - // es6 polyfill - require('@babel/register') - // parse app.body // https://expressjs.com/en/4x/api.html#req.body app.use(bodyParser.json()) diff --git a/mock/remote-search.js b/mock/remote-search.js index 60809cb8..8fc49267 100644 --- a/mock/remote-search.js +++ b/mock/remote-search.js @@ -1,4 +1,4 @@ -import Mock from 'mockjs' +const Mock = require('mockjs') const NameList = [] const count = 100 @@ -10,7 +10,7 @@ for (let i = 0; i < count; i++) { } NameList.push({ name: 'mock-Pan' }) -export default [ +module.exports = [ // username search { url: '/vue-element-admin/search/user', diff --git a/mock/role/index.js b/mock/role/index.js index d957493b..4643f006 100644 --- a/mock/role/index.js +++ b/mock/role/index.js @@ -1,6 +1,6 @@ -import Mock from 'mockjs' -import { deepClone } from '../../src/utils/index.js' -import { asyncRoutes, constantRoutes } from './routes.js' +const Mock = require('mockjs') +const { deepClone } = require('../utils') +const { asyncRoutes, constantRoutes } = require('./routes.js') const routes = deepClone([...constantRoutes, ...asyncRoutes]) @@ -35,7 +35,7 @@ const roles = [ } ] -export default [ +module.exports = [ // mock get all routes form server { url: '/vue-element-admin/routes', diff --git a/mock/role/routes.js b/mock/role/routes.js index d718919c..d33f1624 100644 --- a/mock/role/routes.js +++ b/mock/role/routes.js @@ -1,6 +1,6 @@ // Just a mock data -export const constantRoutes = [ +const constantRoutes = [ { path: '/redirect', component: 'layout/Layout', @@ -72,7 +72,7 @@ export const constantRoutes = [ } ] -export const asyncRoutes = [ +const asyncRoutes = [ { path: '/permission', component: 'layout/Layout', @@ -523,3 +523,8 @@ export const asyncRoutes = [ { path: '*', redirect: '/404', hidden: true } ] + +module.exports = { + constantRoutes, + asyncRoutes +} diff --git a/mock/user.js b/mock/user.js index 859bd6f3..d82e079d 100644 --- a/mock/user.js +++ b/mock/user.js @@ -23,7 +23,7 @@ const users = { } } -export default [ +module.exports = [ // user login { url: '/vue-element-admin/user/login', diff --git a/mock/utils.js b/mock/utils.js new file mode 100644 index 00000000..5bd2d2c9 --- /dev/null +++ b/mock/utils.js @@ -0,0 +1,46 @@ +/** + * @param {string} url + * @returns {Object} + */ +function param2Obj(url) { + const search = url.split('?')[1] + if (!search) { + return {} + } + return JSON.parse( + '{"' + + decodeURIComponent(search) + .replace(/"/g, '\\"') + .replace(/&/g, '","') + .replace(/=/g, '":"') + .replace(/\+/g, ' ') + + '"}' + ) +} + +/** + * This is just a simple version of deep copy + * Has a lot of edge cases bug + * If you want to use a perfect deep copy, use lodash's _.cloneDeep + * @param {Object} source + * @returns {Object} + */ +function deepClone(source) { + if (!source && typeof source !== 'object') { + throw new Error('error arguments', 'deepClone') + } + const targetObj = source.constructor === Array ? [] : {} + Object.keys(source).forEach(keys => { + if (source[keys] && typeof source[keys] === 'object') { + targetObj[keys] = deepClone(source[keys]) + } else { + targetObj[keys] = source[keys] + } + }) + return targetObj +} + +module.exports = { + param2Obj, + deepClone +} diff --git a/package.json b/package.json index 22ebe91e..cded3a4f 100644 --- a/package.json +++ b/package.json @@ -72,8 +72,6 @@ "xlsx": "0.14.1" }, "devDependencies": { - "@babel/core": "7.0.0", - "@babel/register": "7.0.0", "@vue/cli-plugin-babel": "3.5.3", "@vue/cli-plugin-eslint": "^3.9.1", "@vue/cli-plugin-unit-jest": "3.5.3", From fc68f56d130387b0f0320f8611d8e33e76525376 Mon Sep 17 00:00:00 2001 From: Cat73 <Cat7373@users.noreply.github.com> Date: Thu, 11 Jun 2020 13:57:41 +0800 Subject: [PATCH 03/10] feat[Menu]: menu icon support el-icon(#3048) --- src/layout/components/Sidebar/Item.vue | 14 +++++++++++++- src/router/index.js | 6 +++--- src/styles/sidebar.scss | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/layout/components/Sidebar/Item.vue b/src/layout/components/Sidebar/Item.vue index b515f615..aa1f5da4 100644 --- a/src/layout/components/Sidebar/Item.vue +++ b/src/layout/components/Sidebar/Item.vue @@ -17,7 +17,11 @@ export default { const vnodes = [] if (icon) { - vnodes.push(<svg-icon icon-class={icon}/>) + if (icon.includes('el-icon')) { + vnodes.push(<i class={[icon, 'sub-el-icon']} />) + } else { + vnodes.push(<svg-icon icon-class={icon}/>) + } } if (title) { @@ -27,3 +31,11 @@ export default { } } </script> + +<style scoped> +.sub-el-icon { + color: currentColor; + width: 1em; + height: 1em; +} +</style> diff --git a/src/router/index.js b/src/router/index.js index 2e522b2a..9c05f896 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -25,7 +25,7 @@ import nestedRouter from './modules/nested' * meta : { roles: ['admin','editor'] control the page roles (you can set multiple roles) title: 'title' the name show in sidebar and breadcrumb (recommend set) - icon: 'svg-name' the icon show in the sidebar + icon: 'svg-name'/'el-icon-x' the icon show in the sidebar noCache: true if set true, the page will no be cached(default is false) affix: true if set true, the tag will affix in the tags-view breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) @@ -197,14 +197,14 @@ export const asyncRoutes = [ name: 'Example', meta: { title: 'Example', - icon: 'example' + icon: 'el-icon-s-help' }, children: [ { path: 'create', component: () => import('@/views/example/create'), name: 'CreateArticle', - meta: { title: 'Create Article', icon: 'edit' } + meta: { title: 'Create Article', icon: 'el-icon-s-help' } }, { path: 'edit/:id(\\d+)', diff --git a/src/styles/sidebar.scss b/src/styles/sidebar.scss index 3dad4c39..94760cc7 100644 --- a/src/styles/sidebar.scss +++ b/src/styles/sidebar.scss @@ -57,6 +57,11 @@ margin-right: 16px; } + .sub-el-icon { + margin-right: 12px; + margin-left: -2px; + } + .el-menu { border: none; height: 100%; @@ -105,6 +110,10 @@ .svg-icon { margin-left: 20px; } + + .sub-el-icon { + margin-left: 19px; + } } } @@ -118,6 +127,10 @@ margin-left: 20px; } + .sub-el-icon { + margin-left: 19px; + } + .el-submenu__icon-arrow { display: none; } @@ -178,6 +191,10 @@ .svg-icon { margin-right: 16px; } + .sub-el-icon { + margin-right: 12px; + margin-left: -2px; + } } .nest-menu .el-submenu>.el-submenu__title, From a50180f6538aba51074f0152157075337e73a4fd Mon Sep 17 00:00:00 2001 From: MaYuanhai <414199639@qq.com> Date: Thu, 11 Jun 2020 20:18:23 +0800 Subject: [PATCH 04/10] fix[utils]: param2Obj bug when url params includes ==(#3100) --- src/utils/index.js | 28 +++++++++++++++------------- tests/unit/utils/param2Obj.spec.js | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 tests/unit/utils/param2Obj.spec.js diff --git a/src/utils/index.js b/src/utils/index.js index 96ee6e7f..50da2621 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -162,19 +162,21 @@ export function param(json) { * @returns {Object} */ export function param2Obj(url) { - const search = url.split('?')[1] - if (!search) { - return {} - } - return JSON.parse( - '{"' + - decodeURIComponent(search) - .replace(/"/g, '\\"') - .replace(/&/g, '","') - .replace(/=/g, '":"') - .replace(/\+/g, ' ') + - '"}' - ) + const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') + if (!search) { + return {} + } + const obj = {} + const searchArr = search.split('&') + searchArr.forEach(v => { + const index = v.indexOf('=') + if (index !== -1) { + const name = v.substring(0, index) + const val = v.substring(index + 1, v.length) + obj[name] = val + } + }) + return obj } /** diff --git a/tests/unit/utils/param2Obj.spec.js b/tests/unit/utils/param2Obj.spec.js new file mode 100644 index 00000000..e106ed88 --- /dev/null +++ b/tests/unit/utils/param2Obj.spec.js @@ -0,0 +1,14 @@ +import { param2Obj } from '@/utils/index.js' +describe('Utils:param2Obj', () => { + const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95' + + it('param2Obj test', () => { + expect(param2Obj(url)).toEqual({ + name: 'bill', + age: '29', + sex: '1', + field: window.btoa('test'), + key: '测试' + }) + }) +}) From 7702b3d809a312feb2a9eb7c7a70fef3ea0628b8 Mon Sep 17 00:00:00 2001 From: Silentdoer <1010993610@qq.com> Date: Thu, 11 Jun 2020 20:24:17 +0800 Subject: [PATCH 05/10] perf: remove unused showdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 花裤衩 <panfree23@gmail.com> --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index cded3a4f..482d5a48 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "path-to-regexp": "2.4.0", "screenfull": "4.2.0", "script-loader": "0.7.2", - "showdown": "1.9.0", "sortablejs": "1.8.4", "tui-editor": "1.3.3", "vue": "2.6.10", From a87218e2663210be30171b92b29e5ea894f12085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com> Date: Thu, 11 Jun 2020 20:51:10 +0800 Subject: [PATCH 06/10] perf: lint code --- src/utils/index.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/utils/index.js b/src/utils/index.js index 50da2621..3225d3c4 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -162,21 +162,21 @@ export function param(json) { * @returns {Object} */ export function param2Obj(url) { - const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') - if (!search) { - return {} + const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') + if (!search) { + return {} + } + const obj = {} + const searchArr = search.split('&') + searchArr.forEach(v => { + const index = v.indexOf('=') + if (index !== -1) { + const name = v.substring(0, index) + const val = v.substring(index + 1, v.length) + obj[name] = val } - const obj = {} - const searchArr = search.split('&') - searchArr.forEach(v => { - const index = v.indexOf('=') - if (index !== -1) { - const name = v.substring(0, index) - const val = v.substring(index + 1, v.length) - obj[name] = val - } - }) - return obj + }) + return obj } /** From 4e7665c07226cf3bc3278a9af1bf60fe6782cb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com> Date: Thu, 11 Jun 2020 21:02:18 +0800 Subject: [PATCH 07/10] fix[v-permission]: support dynamic set roles (#3251) --- src/directive/permission/permission.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/directive/permission/permission.js b/src/directive/permission/permission.js index b27f24da..49d1f889 100644 --- a/src/directive/permission/permission.js +++ b/src/directive/permission/permission.js @@ -1,11 +1,11 @@ import store from '@/store' -export default { - inserted(el, binding, vnode) { - const { value } = binding - const roles = store.getters && store.getters.roles +function checkPermission(el, binding) { + const { value } = binding + const roles = store.getters && store.getters.roles - if (value && value instanceof Array && value.length > 0) { + if (value && value instanceof Array) { + if (value.length > 0) { const permissionRoles = value const hasPermission = roles.some(role => { @@ -15,8 +15,17 @@ export default { if (!hasPermission) { el.parentNode && el.parentNode.removeChild(el) } - } else { - throw new Error(`need roles! Like v-permission="['admin','editor']"`) } + } else { + throw new Error(`need roles! Like v-permission="['admin','editor']"`) + } +} + +export default { + inserted(el, binding) { + checkPermission(el, binding) + }, + update(el, binding) { + checkPermission(el, binding) } } From 1c943509f9788297f0ddc188208f9501648c8e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com> Date: Fri, 12 Jun 2020 10:18:05 +0800 Subject: [PATCH 08/10] chore: update element-ui to 2.13.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 482d5a48..7f8e8d31 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "driver.js": "0.9.5", "dropzone": "5.5.1", "echarts": "4.2.1", - "element-ui": "2.13.0", + "element-ui": "2.13.2", "file-saver": "2.0.1", "fuse.js": "3.4.4", "js-cookie": "2.2.0", From 6d88db5c73ea54063190830da3d1a40421c51bf3 Mon Sep 17 00:00:00 2001 From: qige2016 <286882998@qq.com> Date: Mon, 15 Jun 2020 12:00:17 +0800 Subject: [PATCH 09/10] fix[plop]: set trim => trim() (#3254) notEmpty --- plop-templates/utils.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/plop-templates/utils.js b/plop-templates/utils.js index 0310ca02..04987539 100644 --- a/plop-templates/utils.js +++ b/plop-templates/utils.js @@ -1,9 +1,2 @@ -exports.notEmpty = name => { - return v => { - if (!v || v.trim === '') { - return `${name} is required` - } else { - return true - } - } -} +exports.notEmpty = name => v => + !v || v.trim() === '' ? `${name} is required` : true From 435db380d3d26a902d6c03092f1aeb2d316b26b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com> Date: Mon, 15 Jun 2020 17:18:55 +0800 Subject: [PATCH 10/10] fix some typos --- mock/utils.js | 22 ++++++++++++---------- src/router/index.js | 2 +- vue.config.js | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/mock/utils.js b/mock/utils.js index 5bd2d2c9..f909a293 100644 --- a/mock/utils.js +++ b/mock/utils.js @@ -3,19 +3,21 @@ * @returns {Object} */ function param2Obj(url) { - const search = url.split('?')[1] + const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') if (!search) { return {} } - return JSON.parse( - '{"' + - decodeURIComponent(search) - .replace(/"/g, '\\"') - .replace(/&/g, '","') - .replace(/=/g, '":"') - .replace(/\+/g, ' ') + - '"}' - ) + const obj = {} + const searchArr = search.split('&') + searchArr.forEach(v => { + const index = v.indexOf('=') + if (index !== -1) { + const name = v.substring(0, index) + const val = v.substring(index + 1, v.length) + obj[name] = val + } + }) + return obj } /** diff --git a/src/router/index.js b/src/router/index.js index 9c05f896..2be959d2 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -204,7 +204,7 @@ export const asyncRoutes = [ path: 'create', component: () => import('@/views/example/create'), name: 'CreateArticle', - meta: { title: 'Create Article', icon: 'el-icon-s-help' } + meta: { title: 'Create Article', icon: 'edit' } }, { path: 'edit/:id(\\d+)', diff --git a/vue.config.js b/vue.config.js index aabbf651..6733dd50 100644 --- a/vue.config.js +++ b/vue.config.js @@ -53,7 +53,7 @@ module.exports = { // config.plugins.delete('preload') // when there are many pages, it will cause too many meaningless requests - config.plugins.delete('prefetch') // + config.plugins.delete('prefetch') // set svg-sprite-loader config.module