zetan-cli-dev-template-vue-element-admin 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +8 -0
- package/template/.editorconfig +14 -0
- package/template/.env.development +5 -0
- package/template/.env.production +6 -0
- package/template/.env.staging +8 -0
- package/template/.eslintignore +4 -0
- package/template/.eslintrc.js +198 -0
- package/template/.travis.yml +5 -0
- package/template/LICENSE +21 -0
- package/template/README.es.md +228 -0
- package/template/README.ja.md +224 -0
- package/template/README.md +250 -0
- package/template/README.zh-CN.md +273 -0
- package/template/babel.config.js +14 -0
- package/template/build/index.js +35 -0
- package/template/jest.config.js +24 -0
- package/template/jsconfig.json +9 -0
- package/template/mock/article.js +116 -0
- package/template/mock/index.js +60 -0
- package/template/mock/mock-server.js +81 -0
- package/template/mock/remote-search.js +51 -0
- package/template/mock/role/index.js +98 -0
- package/template/mock/role/routes.js +530 -0
- package/template/mock/user.js +84 -0
- package/template/mock/utils.js +48 -0
- package/template/package.json +111 -0
- package/template/plop-templates/component/index.hbs +26 -0
- package/template/plop-templates/component/prompt.js +55 -0
- package/template/plop-templates/store/index.hbs +16 -0
- package/template/plop-templates/store/prompt.js +62 -0
- package/template/plop-templates/utils.js +2 -0
- package/template/plop-templates/view/index.hbs +26 -0
- package/template/plop-templates/view/prompt.js +55 -0
- package/template/plopfile.js +9 -0
- package/template/postcss.config.js +5 -0
- package/template/public/favicon.ico +0 -0
- package/template/public/index.html +15 -0
- package/template/src/App.vue +11 -0
- package/template/src/api/article.js +41 -0
- package/template/src/api/qiniu.js +8 -0
- package/template/src/api/remote-search.js +17 -0
- package/template/src/api/role.js +38 -0
- package/template/src/api/user.js +24 -0
- package/template/src/assets/401_images/401.gif +0 -0
- package/template/src/assets/404_images/404.png +0 -0
- package/template/src/assets/404_images/404_cloud.png +0 -0
- package/template/src/assets/custom-theme/fonts/element-icons.ttf +0 -0
- package/template/src/assets/custom-theme/fonts/element-icons.woff +0 -0
- package/template/src/assets/custom-theme/index.css +1 -0
- package/template/src/components/BackToTop/index.vue +111 -0
- package/template/src/components/Breadcrumb/index.vue +82 -0
- package/template/src/components/Charts/Keyboard.vue +155 -0
- package/template/src/components/Charts/LineMarker.vue +227 -0
- package/template/src/components/Charts/MixChart.vue +271 -0
- package/template/src/components/Charts/mixins/resize.js +56 -0
- package/template/src/components/DndList/index.vue +166 -0
- package/template/src/components/DragSelect/index.vue +65 -0
- package/template/src/components/Dropzone/index.vue +297 -0
- package/template/src/components/ErrorLog/index.vue +78 -0
- package/template/src/components/GithubCorner/index.vue +54 -0
- package/template/src/components/Hamburger/index.vue +44 -0
- package/template/src/components/HeaderSearch/index.vue +180 -0
- package/template/src/components/ImageCropper/index.vue +1779 -0
- package/template/src/components/ImageCropper/utils/data2blob.js +19 -0
- package/template/src/components/ImageCropper/utils/effectRipple.js +39 -0
- package/template/src/components/ImageCropper/utils/language.js +232 -0
- package/template/src/components/ImageCropper/utils/mimes.js +7 -0
- package/template/src/components/JsonEditor/index.vue +77 -0
- package/template/src/components/Kanban/index.vue +99 -0
- package/template/src/components/MDinput/index.vue +360 -0
- package/template/src/components/MarkdownEditor/default-options.js +31 -0
- package/template/src/components/MarkdownEditor/index.vue +118 -0
- package/template/src/components/Pagination/index.vue +101 -0
- package/template/src/components/PanThumb/index.vue +142 -0
- package/template/src/components/RightPanel/index.vue +145 -0
- package/template/src/components/Screenfull/index.vue +60 -0
- package/template/src/components/Share/DropdownMenu.vue +103 -0
- package/template/src/components/SizeSelect/index.vue +57 -0
- package/template/src/components/Sticky/index.vue +91 -0
- package/template/src/components/SvgIcon/index.vue +62 -0
- package/template/src/components/TextHoverEffect/Mallki.vue +113 -0
- package/template/src/components/ThemePicker/index.vue +175 -0
- package/template/src/components/Tinymce/components/EditorImage.vue +111 -0
- package/template/src/components/Tinymce/dynamicLoadScript.js +59 -0
- package/template/src/components/Tinymce/index.vue +247 -0
- package/template/src/components/Tinymce/plugins.js +7 -0
- package/template/src/components/Tinymce/toolbar.js +6 -0
- package/template/src/components/Upload/SingleImage.vue +134 -0
- package/template/src/components/Upload/SingleImage2.vue +130 -0
- package/template/src/components/Upload/SingleImage3.vue +157 -0
- package/template/src/components/UploadExcel/index.vue +138 -0
- package/template/src/directive/clipboard/clipboard.js +49 -0
- package/template/src/directive/clipboard/index.js +13 -0
- package/template/src/directive/el-drag-dialog/drag.js +77 -0
- package/template/src/directive/el-drag-dialog/index.js +13 -0
- package/template/src/directive/el-table/adaptive.js +41 -0
- package/template/src/directive/el-table/index.js +13 -0
- package/template/src/directive/permission/index.js +13 -0
- package/template/src/directive/permission/permission.js +31 -0
- package/template/src/directive/sticky.js +91 -0
- package/template/src/directive/waves/index.js +13 -0
- package/template/src/directive/waves/waves.css +26 -0
- package/template/src/directive/waves/waves.js +72 -0
- package/template/src/filters/index.js +68 -0
- package/template/src/icons/index.js +9 -0
- package/template/src/icons/svg/404.svg +1 -0
- package/template/src/icons/svg/bug.svg +1 -0
- package/template/src/icons/svg/chart.svg +1 -0
- package/template/src/icons/svg/clipboard.svg +1 -0
- package/template/src/icons/svg/component.svg +1 -0
- package/template/src/icons/svg/dashboard.svg +1 -0
- package/template/src/icons/svg/documentation.svg +1 -0
- package/template/src/icons/svg/drag.svg +1 -0
- package/template/src/icons/svg/edit.svg +1 -0
- package/template/src/icons/svg/education.svg +1 -0
- package/template/src/icons/svg/email.svg +1 -0
- package/template/src/icons/svg/example.svg +1 -0
- package/template/src/icons/svg/excel.svg +1 -0
- package/template/src/icons/svg/exit-fullscreen.svg +1 -0
- package/template/src/icons/svg/eye-open.svg +1 -0
- package/template/src/icons/svg/eye.svg +1 -0
- package/template/src/icons/svg/form.svg +1 -0
- package/template/src/icons/svg/fullscreen.svg +1 -0
- package/template/src/icons/svg/guide.svg +1 -0
- package/template/src/icons/svg/icon.svg +1 -0
- package/template/src/icons/svg/international.svg +1 -0
- package/template/src/icons/svg/language.svg +1 -0
- package/template/src/icons/svg/link.svg +1 -0
- package/template/src/icons/svg/list.svg +1 -0
- package/template/src/icons/svg/lock.svg +1 -0
- package/template/src/icons/svg/message.svg +1 -0
- package/template/src/icons/svg/money.svg +1 -0
- package/template/src/icons/svg/nested.svg +1 -0
- package/template/src/icons/svg/password.svg +1 -0
- package/template/src/icons/svg/pdf.svg +1 -0
- package/template/src/icons/svg/people.svg +1 -0
- package/template/src/icons/svg/peoples.svg +1 -0
- package/template/src/icons/svg/qq.svg +1 -0
- package/template/src/icons/svg/search.svg +1 -0
- package/template/src/icons/svg/shopping.svg +1 -0
- package/template/src/icons/svg/size.svg +1 -0
- package/template/src/icons/svg/skill.svg +1 -0
- package/template/src/icons/svg/star.svg +1 -0
- package/template/src/icons/svg/tab.svg +1 -0
- package/template/src/icons/svg/table.svg +1 -0
- package/template/src/icons/svg/theme.svg +1 -0
- package/template/src/icons/svg/tree-table.svg +1 -0
- package/template/src/icons/svg/tree.svg +1 -0
- package/template/src/icons/svg/user.svg +1 -0
- package/template/src/icons/svg/wechat.svg +1 -0
- package/template/src/icons/svg/zip.svg +1 -0
- package/template/src/icons/svgo.yml +22 -0
- package/template/src/layout/components/AppMain.vue +57 -0
- package/template/src/layout/components/Navbar.vue +167 -0
- package/template/src/layout/components/Settings/index.vue +108 -0
- package/template/src/layout/components/Sidebar/FixiOSBug.js +26 -0
- package/template/src/layout/components/Sidebar/Item.vue +41 -0
- package/template/src/layout/components/Sidebar/Link.vue +43 -0
- package/template/src/layout/components/Sidebar/Logo.vue +82 -0
- package/template/src/layout/components/Sidebar/SidebarItem.vue +95 -0
- package/template/src/layout/components/Sidebar/index.vue +54 -0
- package/template/src/layout/components/TagsView/ScrollPane.vue +94 -0
- package/template/src/layout/components/TagsView/index.vue +292 -0
- package/template/src/layout/components/index.js +5 -0
- package/template/src/layout/index.vue +102 -0
- package/template/src/layout/mixin/ResizeHandler.js +45 -0
- package/template/src/main.js +53 -0
- package/template/src/permission.js +74 -0
- package/template/src/router/index.js +404 -0
- package/template/src/router/modules/charts.js +36 -0
- package/template/src/router/modules/components.js +102 -0
- package/template/src/router/modules/nested.js +66 -0
- package/template/src/router/modules/table.js +41 -0
- package/template/src/settings.js +35 -0
- package/template/src/store/getters.js +15 -0
- package/template/src/store/index.js +25 -0
- package/template/src/store/modules/app.js +56 -0
- package/template/src/store/modules/errorLog.js +28 -0
- package/template/src/store/modules/permission.js +69 -0
- package/template/src/store/modules/settings.js +35 -0
- package/template/src/store/modules/tagsView.js +160 -0
- package/template/src/store/modules/user.js +131 -0
- package/template/src/styles/btn.scss +99 -0
- package/template/src/styles/element-ui.scss +84 -0
- package/template/src/styles/element-variables.scss +31 -0
- package/template/src/styles/index.scss +191 -0
- package/template/src/styles/mixin.scss +66 -0
- package/template/src/styles/sidebar.scss +226 -0
- package/template/src/styles/transition.scss +48 -0
- package/template/src/styles/variables.scss +35 -0
- package/template/src/utils/auth.js +15 -0
- package/template/src/utils/clipboard.js +32 -0
- package/template/src/utils/error-log.js +35 -0
- package/template/src/utils/get-page-title.js +10 -0
- package/template/src/utils/index.js +357 -0
- package/template/src/utils/open-window.js +25 -0
- package/template/src/utils/permission.js +21 -0
- package/template/src/utils/request.js +85 -0
- package/template/src/utils/scroll-to.js +58 -0
- package/template/src/utils/validate.js +87 -0
- package/template/src/vendor/Export2Excel.js +220 -0
- package/template/src/vendor/Export2Zip.js +24 -0
- package/template/src/views/charts/keyboard.vue +23 -0
- package/template/src/views/charts/line.vue +23 -0
- package/template/src/views/charts/mix-chart.vue +23 -0
- package/template/src/views/clipboard/index.vue +49 -0
- package/template/src/views/components-demo/avatar-upload.vue +61 -0
- package/template/src/views/components-demo/back-to-top.vue +154 -0
- package/template/src/views/components-demo/count-to.vue +218 -0
- package/template/src/views/components-demo/dnd-list.vue +39 -0
- package/template/src/views/components-demo/drag-dialog.vue +61 -0
- package/template/src/views/components-demo/drag-kanban.vue +66 -0
- package/template/src/views/components-demo/drag-select.vue +43 -0
- package/template/src/views/components-demo/dropzone.vue +31 -0
- package/template/src/views/components-demo/json-editor.vue +36 -0
- package/template/src/views/components-demo/markdown.vue +101 -0
- package/template/src/views/components-demo/mixin.vue +169 -0
- package/template/src/views/components-demo/split-pane.vue +67 -0
- package/template/src/views/components-demo/sticky.vue +135 -0
- package/template/src/views/components-demo/tinymce.vue +36 -0
- package/template/src/views/dashboard/admin/components/BarChart.vue +102 -0
- package/template/src/views/dashboard/admin/components/BoxCard.vue +118 -0
- package/template/src/views/dashboard/admin/components/LineChart.vue +135 -0
- package/template/src/views/dashboard/admin/components/PanelGroup.vue +181 -0
- package/template/src/views/dashboard/admin/components/PieChart.vue +79 -0
- package/template/src/views/dashboard/admin/components/RaddarChart.vue +116 -0
- package/template/src/views/dashboard/admin/components/TodoList/Todo.vue +81 -0
- package/template/src/views/dashboard/admin/components/TodoList/index.scss +320 -0
- package/template/src/views/dashboard/admin/components/TodoList/index.vue +127 -0
- package/template/src/views/dashboard/admin/components/TransactionTable.vue +55 -0
- package/template/src/views/dashboard/admin/components/mixins/resize.js +55 -0
- package/template/src/views/dashboard/admin/index.vue +124 -0
- package/template/src/views/dashboard/editor/index.vue +74 -0
- package/template/src/views/dashboard/index.vue +31 -0
- package/template/src/views/documentation/index.vue +57 -0
- package/template/src/views/error-log/components/ErrorTestA.vue +13 -0
- package/template/src/views/error-log/components/ErrorTestB.vue +11 -0
- package/template/src/views/error-log/index.vue +32 -0
- package/template/src/views/error-page/401.vue +99 -0
- package/template/src/views/error-page/404.vue +228 -0
- package/template/src/views/example/components/ArticleDetail.vue +289 -0
- package/template/src/views/example/components/Dropdown/Comment.vue +41 -0
- package/template/src/views/example/components/Dropdown/Platform.vue +46 -0
- package/template/src/views/example/components/Dropdown/SourceUrl.vue +38 -0
- package/template/src/views/example/components/Dropdown/index.js +3 -0
- package/template/src/views/example/components/Warning.vue +13 -0
- package/template/src/views/example/create.vue +13 -0
- package/template/src/views/example/edit.vue +13 -0
- package/template/src/views/example/list.vue +112 -0
- package/template/src/views/excel/components/AutoWidthOption.vue +34 -0
- package/template/src/views/excel/components/BookTypeOption.vue +39 -0
- package/template/src/views/excel/components/FilenameOption.vue +27 -0
- package/template/src/views/excel/export-excel.vue +116 -0
- package/template/src/views/excel/merge-header.vue +101 -0
- package/template/src/views/excel/select-excel.vue +107 -0
- package/template/src/views/excel/upload-excel.vue +42 -0
- package/template/src/views/guide/index.vue +36 -0
- package/template/src/views/guide/steps.js +53 -0
- package/template/src/views/icons/element-icons.js +3 -0
- package/template/src/views/icons/index.vue +101 -0
- package/template/src/views/icons/svg-icons.js +10 -0
- package/template/src/views/login/auth-redirect.vue +15 -0
- package/template/src/views/login/components/SocialSignin.vue +72 -0
- package/template/src/views/login/index.vue +324 -0
- package/template/src/views/nested/menu1/index.vue +7 -0
- package/template/src/views/nested/menu1/menu1-1/index.vue +7 -0
- package/template/src/views/nested/menu1/menu1-2/index.vue +7 -0
- package/template/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue +5 -0
- package/template/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue +5 -0
- package/template/src/views/nested/menu1/menu1-3/index.vue +5 -0
- package/template/src/views/nested/menu2/index.vue +5 -0
- package/template/src/views/pdf/content.js +58 -0
- package/template/src/views/pdf/download.vue +201 -0
- package/template/src/views/pdf/index.vue +13 -0
- package/template/src/views/permission/components/SwitchRoles.vue +32 -0
- package/template/src/views/permission/directive.vue +111 -0
- package/template/src/views/permission/page.vue +19 -0
- package/template/src/views/permission/role.vue +270 -0
- package/template/src/views/profile/components/Account.vue +38 -0
- package/template/src/views/profile/components/Activity.vue +185 -0
- package/template/src/views/profile/components/Timeline.vue +43 -0
- package/template/src/views/profile/components/UserCard.vue +134 -0
- package/template/src/views/profile/index.vue +68 -0
- package/template/src/views/qiniu/upload.vue +41 -0
- package/template/src/views/redirect/index.vue +12 -0
- package/template/src/views/tab/components/TabPane.vue +103 -0
- package/template/src/views/tab/index.vue +57 -0
- package/template/src/views/table/complex-table.vue +379 -0
- package/template/src/views/table/drag-table.vue +153 -0
- package/template/src/views/table/dynamic-table/components/FixedThead.vue +62 -0
- package/template/src/views/table/dynamic-table/components/UnfixedThead.vue +50 -0
- package/template/src/views/table/dynamic-table/index.vue +24 -0
- package/template/src/views/table/inline-edit-table.vue +149 -0
- package/template/src/views/theme/index.vue +120 -0
- package/template/src/views/zip/index.vue +77 -0
- package/template/tests/unit/.eslintrc.js +5 -0
- package/template/tests/unit/components/Hamburger.spec.js +18 -0
- package/template/tests/unit/components/SvgIcon.spec.js +22 -0
- package/template/tests/unit/utils/formatTime.spec.js +29 -0
- package/template/tests/unit/utils/param2Obj.spec.js +14 -0
- package/template/tests/unit/utils/parseTime.spec.js +37 -0
- package/template/tests/unit/utils/validate.spec.js +28 -0
- package/template/vue.config.js +124 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
import Vue from 'vue'
|
2
|
+
import store from '@/store'
|
3
|
+
import { isString, isArray } from '@/utils/validate'
|
4
|
+
import settings from '@/settings'
|
5
|
+
|
6
|
+
// you can set in settings.js
|
7
|
+
// errorLog:'production' | ['production', 'development']
|
8
|
+
const { errorLog: needErrorLog } = settings
|
9
|
+
|
10
|
+
function checkNeed() {
|
11
|
+
const env = process.env.NODE_ENV
|
12
|
+
if (isString(needErrorLog)) {
|
13
|
+
return env === needErrorLog
|
14
|
+
}
|
15
|
+
if (isArray(needErrorLog)) {
|
16
|
+
return needErrorLog.includes(env)
|
17
|
+
}
|
18
|
+
return false
|
19
|
+
}
|
20
|
+
|
21
|
+
if (checkNeed()) {
|
22
|
+
Vue.config.errorHandler = function(err, vm, info, a) {
|
23
|
+
// Don't ask me why I use Vue.nextTick, it just a hack.
|
24
|
+
// detail see https://forum.vuejs.org/t/dispatch-in-vue-config-errorhandler-has-some-problem/23500
|
25
|
+
Vue.nextTick(() => {
|
26
|
+
store.dispatch('errorLog/addErrorLog', {
|
27
|
+
err,
|
28
|
+
vm,
|
29
|
+
info,
|
30
|
+
url: window.location.href
|
31
|
+
})
|
32
|
+
console.error(err, info)
|
33
|
+
})
|
34
|
+
}
|
35
|
+
}
|
@@ -0,0 +1,357 @@
|
|
1
|
+
/**
|
2
|
+
* Created by PanJiaChen on 16/11/18.
|
3
|
+
*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Parse the time to string
|
7
|
+
* @param {(Object|string|number)} time
|
8
|
+
* @param {string} cFormat
|
9
|
+
* @returns {string | null}
|
10
|
+
*/
|
11
|
+
export function parseTime(time, cFormat) {
|
12
|
+
if (arguments.length === 0 || !time) {
|
13
|
+
return null
|
14
|
+
}
|
15
|
+
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
16
|
+
let date
|
17
|
+
if (typeof time === 'object') {
|
18
|
+
date = time
|
19
|
+
} else {
|
20
|
+
if ((typeof time === 'string')) {
|
21
|
+
if ((/^[0-9]+$/.test(time))) {
|
22
|
+
// support "1548221490638"
|
23
|
+
time = parseInt(time)
|
24
|
+
} else {
|
25
|
+
// support safari
|
26
|
+
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
|
27
|
+
time = time.replace(new RegExp(/-/gm), '/')
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
if ((typeof time === 'number') && (time.toString().length === 10)) {
|
32
|
+
time = time * 1000
|
33
|
+
}
|
34
|
+
date = new Date(time)
|
35
|
+
}
|
36
|
+
const formatObj = {
|
37
|
+
y: date.getFullYear(),
|
38
|
+
m: date.getMonth() + 1,
|
39
|
+
d: date.getDate(),
|
40
|
+
h: date.getHours(),
|
41
|
+
i: date.getMinutes(),
|
42
|
+
s: date.getSeconds(),
|
43
|
+
a: date.getDay()
|
44
|
+
}
|
45
|
+
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
|
46
|
+
const value = formatObj[key]
|
47
|
+
// Note: getDay() returns 0 on Sunday
|
48
|
+
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
|
49
|
+
return value.toString().padStart(2, '0')
|
50
|
+
})
|
51
|
+
return time_str
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* @param {number} time
|
56
|
+
* @param {string} option
|
57
|
+
* @returns {string}
|
58
|
+
*/
|
59
|
+
export function formatTime(time, option) {
|
60
|
+
if (('' + time).length === 10) {
|
61
|
+
time = parseInt(time) * 1000
|
62
|
+
} else {
|
63
|
+
time = +time
|
64
|
+
}
|
65
|
+
const d = new Date(time)
|
66
|
+
const now = Date.now()
|
67
|
+
|
68
|
+
const diff = (now - d) / 1000
|
69
|
+
|
70
|
+
if (diff < 30) {
|
71
|
+
return '刚刚'
|
72
|
+
} else if (diff < 3600) {
|
73
|
+
// less 1 hour
|
74
|
+
return Math.ceil(diff / 60) + '分钟前'
|
75
|
+
} else if (diff < 3600 * 24) {
|
76
|
+
return Math.ceil(diff / 3600) + '小时前'
|
77
|
+
} else if (diff < 3600 * 24 * 2) {
|
78
|
+
return '1天前'
|
79
|
+
}
|
80
|
+
if (option) {
|
81
|
+
return parseTime(time, option)
|
82
|
+
} else {
|
83
|
+
return (
|
84
|
+
d.getMonth() +
|
85
|
+
1 +
|
86
|
+
'月' +
|
87
|
+
d.getDate() +
|
88
|
+
'日' +
|
89
|
+
d.getHours() +
|
90
|
+
'时' +
|
91
|
+
d.getMinutes() +
|
92
|
+
'分'
|
93
|
+
)
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* @param {string} url
|
99
|
+
* @returns {Object}
|
100
|
+
*/
|
101
|
+
export function getQueryObject(url) {
|
102
|
+
url = url == null ? window.location.href : url
|
103
|
+
const search = url.substring(url.lastIndexOf('?') + 1)
|
104
|
+
const obj = {}
|
105
|
+
const reg = /([^?&=]+)=([^?&=]*)/g
|
106
|
+
search.replace(reg, (rs, $1, $2) => {
|
107
|
+
const name = decodeURIComponent($1)
|
108
|
+
let val = decodeURIComponent($2)
|
109
|
+
val = String(val)
|
110
|
+
obj[name] = val
|
111
|
+
return rs
|
112
|
+
})
|
113
|
+
return obj
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* @param {string} input value
|
118
|
+
* @returns {number} output value
|
119
|
+
*/
|
120
|
+
export function byteLength(str) {
|
121
|
+
// returns the byte length of an utf8 string
|
122
|
+
let s = str.length
|
123
|
+
for (var i = str.length - 1; i >= 0; i--) {
|
124
|
+
const code = str.charCodeAt(i)
|
125
|
+
if (code > 0x7f && code <= 0x7ff) s++
|
126
|
+
else if (code > 0x7ff && code <= 0xffff) s += 2
|
127
|
+
if (code >= 0xDC00 && code <= 0xDFFF) i--
|
128
|
+
}
|
129
|
+
return s
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* @param {Array} actual
|
134
|
+
* @returns {Array}
|
135
|
+
*/
|
136
|
+
export function cleanArray(actual) {
|
137
|
+
const newArray = []
|
138
|
+
for (let i = 0; i < actual.length; i++) {
|
139
|
+
if (actual[i]) {
|
140
|
+
newArray.push(actual[i])
|
141
|
+
}
|
142
|
+
}
|
143
|
+
return newArray
|
144
|
+
}
|
145
|
+
|
146
|
+
/**
|
147
|
+
* @param {Object} json
|
148
|
+
* @returns {Array}
|
149
|
+
*/
|
150
|
+
export function param(json) {
|
151
|
+
if (!json) return ''
|
152
|
+
return cleanArray(
|
153
|
+
Object.keys(json).map(key => {
|
154
|
+
if (json[key] === undefined) return ''
|
155
|
+
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
|
156
|
+
})
|
157
|
+
).join('&')
|
158
|
+
}
|
159
|
+
|
160
|
+
/**
|
161
|
+
* @param {string} url
|
162
|
+
* @returns {Object}
|
163
|
+
*/
|
164
|
+
export function param2Obj(url) {
|
165
|
+
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
|
166
|
+
if (!search) {
|
167
|
+
return {}
|
168
|
+
}
|
169
|
+
const obj = {}
|
170
|
+
const searchArr = search.split('&')
|
171
|
+
searchArr.forEach(v => {
|
172
|
+
const index = v.indexOf('=')
|
173
|
+
if (index !== -1) {
|
174
|
+
const name = v.substring(0, index)
|
175
|
+
const val = v.substring(index + 1, v.length)
|
176
|
+
obj[name] = val
|
177
|
+
}
|
178
|
+
})
|
179
|
+
return obj
|
180
|
+
}
|
181
|
+
|
182
|
+
/**
|
183
|
+
* @param {string} val
|
184
|
+
* @returns {string}
|
185
|
+
*/
|
186
|
+
export function html2Text(val) {
|
187
|
+
const div = document.createElement('div')
|
188
|
+
div.innerHTML = val
|
189
|
+
return div.textContent || div.innerText
|
190
|
+
}
|
191
|
+
|
192
|
+
/**
|
193
|
+
* Merges two objects, giving the last one precedence
|
194
|
+
* @param {Object} target
|
195
|
+
* @param {(Object|Array)} source
|
196
|
+
* @returns {Object}
|
197
|
+
*/
|
198
|
+
export function objectMerge(target, source) {
|
199
|
+
if (typeof target !== 'object') {
|
200
|
+
target = {}
|
201
|
+
}
|
202
|
+
if (Array.isArray(source)) {
|
203
|
+
return source.slice()
|
204
|
+
}
|
205
|
+
Object.keys(source).forEach(property => {
|
206
|
+
const sourceProperty = source[property]
|
207
|
+
if (typeof sourceProperty === 'object') {
|
208
|
+
target[property] = objectMerge(target[property], sourceProperty)
|
209
|
+
} else {
|
210
|
+
target[property] = sourceProperty
|
211
|
+
}
|
212
|
+
})
|
213
|
+
return target
|
214
|
+
}
|
215
|
+
|
216
|
+
/**
|
217
|
+
* @param {HTMLElement} element
|
218
|
+
* @param {string} className
|
219
|
+
*/
|
220
|
+
export function toggleClass(element, className) {
|
221
|
+
if (!element || !className) {
|
222
|
+
return
|
223
|
+
}
|
224
|
+
let classString = element.className
|
225
|
+
const nameIndex = classString.indexOf(className)
|
226
|
+
if (nameIndex === -1) {
|
227
|
+
classString += '' + className
|
228
|
+
} else {
|
229
|
+
classString =
|
230
|
+
classString.substr(0, nameIndex) +
|
231
|
+
classString.substr(nameIndex + className.length)
|
232
|
+
}
|
233
|
+
element.className = classString
|
234
|
+
}
|
235
|
+
|
236
|
+
/**
|
237
|
+
* @param {string} type
|
238
|
+
* @returns {Date}
|
239
|
+
*/
|
240
|
+
export function getTime(type) {
|
241
|
+
if (type === 'start') {
|
242
|
+
return new Date().getTime() - 3600 * 1000 * 24 * 90
|
243
|
+
} else {
|
244
|
+
return new Date(new Date().toDateString())
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
/**
|
249
|
+
* @param {Function} func
|
250
|
+
* @param {number} wait
|
251
|
+
* @param {boolean} immediate
|
252
|
+
* @return {*}
|
253
|
+
*/
|
254
|
+
export function debounce(func, wait, immediate) {
|
255
|
+
let timeout, args, context, timestamp, result
|
256
|
+
|
257
|
+
const later = function() {
|
258
|
+
// 据上一次触发时间间隔
|
259
|
+
const last = +new Date() - timestamp
|
260
|
+
|
261
|
+
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
|
262
|
+
if (last < wait && last > 0) {
|
263
|
+
timeout = setTimeout(later, wait - last)
|
264
|
+
} else {
|
265
|
+
timeout = null
|
266
|
+
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
|
267
|
+
if (!immediate) {
|
268
|
+
result = func.apply(context, args)
|
269
|
+
if (!timeout) context = args = null
|
270
|
+
}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
return function(...args) {
|
275
|
+
context = this
|
276
|
+
timestamp = +new Date()
|
277
|
+
const callNow = immediate && !timeout
|
278
|
+
// 如果延时不存在,重新设定延时
|
279
|
+
if (!timeout) timeout = setTimeout(later, wait)
|
280
|
+
if (callNow) {
|
281
|
+
result = func.apply(context, args)
|
282
|
+
context = args = null
|
283
|
+
}
|
284
|
+
|
285
|
+
return result
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
/**
|
290
|
+
* This is just a simple version of deep copy
|
291
|
+
* Has a lot of edge cases bug
|
292
|
+
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
|
293
|
+
* @param {Object} source
|
294
|
+
* @returns {Object}
|
295
|
+
*/
|
296
|
+
export function deepClone(source) {
|
297
|
+
if (!source && typeof source !== 'object') {
|
298
|
+
throw new Error('error arguments', 'deepClone')
|
299
|
+
}
|
300
|
+
const targetObj = source.constructor === Array ? [] : {}
|
301
|
+
Object.keys(source).forEach(keys => {
|
302
|
+
if (source[keys] && typeof source[keys] === 'object') {
|
303
|
+
targetObj[keys] = deepClone(source[keys])
|
304
|
+
} else {
|
305
|
+
targetObj[keys] = source[keys]
|
306
|
+
}
|
307
|
+
})
|
308
|
+
return targetObj
|
309
|
+
}
|
310
|
+
|
311
|
+
/**
|
312
|
+
* @param {Array} arr
|
313
|
+
* @returns {Array}
|
314
|
+
*/
|
315
|
+
export function uniqueArr(arr) {
|
316
|
+
return Array.from(new Set(arr))
|
317
|
+
}
|
318
|
+
|
319
|
+
/**
|
320
|
+
* @returns {string}
|
321
|
+
*/
|
322
|
+
export function createUniqueString() {
|
323
|
+
const timestamp = +new Date() + ''
|
324
|
+
const randomNum = parseInt((1 + Math.random()) * 65536) + ''
|
325
|
+
return (+(randomNum + timestamp)).toString(32)
|
326
|
+
}
|
327
|
+
|
328
|
+
/**
|
329
|
+
* Check if an element has a class
|
330
|
+
* @param {HTMLElement} elm
|
331
|
+
* @param {string} cls
|
332
|
+
* @returns {boolean}
|
333
|
+
*/
|
334
|
+
export function hasClass(ele, cls) {
|
335
|
+
return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
|
336
|
+
}
|
337
|
+
|
338
|
+
/**
|
339
|
+
* Add class to element
|
340
|
+
* @param {HTMLElement} elm
|
341
|
+
* @param {string} cls
|
342
|
+
*/
|
343
|
+
export function addClass(ele, cls) {
|
344
|
+
if (!hasClass(ele, cls)) ele.className += ' ' + cls
|
345
|
+
}
|
346
|
+
|
347
|
+
/**
|
348
|
+
* Remove class from element
|
349
|
+
* @param {HTMLElement} elm
|
350
|
+
* @param {string} cls
|
351
|
+
*/
|
352
|
+
export function removeClass(ele, cls) {
|
353
|
+
if (hasClass(ele, cls)) {
|
354
|
+
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
|
355
|
+
ele.className = ele.className.replace(reg, ' ')
|
356
|
+
}
|
357
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
*Created by PanJiaChen on 16/11/29.
|
3
|
+
* @param {Sting} url
|
4
|
+
* @param {Sting} title
|
5
|
+
* @param {Number} w
|
6
|
+
* @param {Number} h
|
7
|
+
*/
|
8
|
+
export default function openWindow(url, title, w, h) {
|
9
|
+
// Fixes dual-screen position Most browsers Firefox
|
10
|
+
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left
|
11
|
+
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top
|
12
|
+
|
13
|
+
const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width
|
14
|
+
const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height
|
15
|
+
|
16
|
+
const left = ((width / 2) - (w / 2)) + dualScreenLeft
|
17
|
+
const top = ((height / 2) - (h / 2)) + dualScreenTop
|
18
|
+
const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left)
|
19
|
+
|
20
|
+
// Puts focus on the newWindow
|
21
|
+
if (window.focus) {
|
22
|
+
newWindow.focus()
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import store from '@/store'
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @param {Array} value
|
5
|
+
* @returns {Boolean}
|
6
|
+
* @example see @/views/permission/directive.vue
|
7
|
+
*/
|
8
|
+
export default function checkPermission(value) {
|
9
|
+
if (value && value instanceof Array && value.length > 0) {
|
10
|
+
const roles = store.getters && store.getters.roles
|
11
|
+
const permissionRoles = value
|
12
|
+
|
13
|
+
const hasPermission = roles.some(role => {
|
14
|
+
return permissionRoles.includes(role)
|
15
|
+
})
|
16
|
+
return hasPermission
|
17
|
+
} else {
|
18
|
+
console.error(`need roles! Like v-permission="['admin','editor']"`)
|
19
|
+
return false
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import axios from 'axios'
|
2
|
+
import { MessageBox, Message } from 'element-ui'
|
3
|
+
import store from '@/store'
|
4
|
+
import { getToken } from '@/utils/auth'
|
5
|
+
|
6
|
+
// create an axios instance
|
7
|
+
const service = axios.create({
|
8
|
+
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
9
|
+
// withCredentials: true, // send cookies when cross-domain requests
|
10
|
+
timeout: 5000 // request timeout
|
11
|
+
})
|
12
|
+
|
13
|
+
// request interceptor
|
14
|
+
service.interceptors.request.use(
|
15
|
+
config => {
|
16
|
+
// do something before request is sent
|
17
|
+
|
18
|
+
if (store.getters.token) {
|
19
|
+
// let each request carry token
|
20
|
+
// ['X-Token'] is a custom headers key
|
21
|
+
// please modify it according to the actual situation
|
22
|
+
config.headers['X-Token'] = getToken()
|
23
|
+
}
|
24
|
+
return config
|
25
|
+
},
|
26
|
+
error => {
|
27
|
+
// do something with request error
|
28
|
+
console.log(error) // for debug
|
29
|
+
return Promise.reject(error)
|
30
|
+
}
|
31
|
+
)
|
32
|
+
|
33
|
+
// response interceptor
|
34
|
+
service.interceptors.response.use(
|
35
|
+
/**
|
36
|
+
* If you want to get http information such as headers or status
|
37
|
+
* Please return response => response
|
38
|
+
*/
|
39
|
+
|
40
|
+
/**
|
41
|
+
* Determine the request status by custom code
|
42
|
+
* Here is just an example
|
43
|
+
* You can also judge the status by HTTP Status Code
|
44
|
+
*/
|
45
|
+
response => {
|
46
|
+
const res = response.data
|
47
|
+
|
48
|
+
// if the custom code is not 20000, it is judged as an error.
|
49
|
+
if (res.code !== 20000) {
|
50
|
+
Message({
|
51
|
+
message: res.message || 'Error',
|
52
|
+
type: 'error',
|
53
|
+
duration: 5 * 1000
|
54
|
+
})
|
55
|
+
|
56
|
+
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
57
|
+
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
|
58
|
+
// to re-login
|
59
|
+
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
|
60
|
+
confirmButtonText: 'Re-Login',
|
61
|
+
cancelButtonText: 'Cancel',
|
62
|
+
type: 'warning'
|
63
|
+
}).then(() => {
|
64
|
+
store.dispatch('user/resetToken').then(() => {
|
65
|
+
location.reload()
|
66
|
+
})
|
67
|
+
})
|
68
|
+
}
|
69
|
+
return Promise.reject(new Error(res.message || 'Error'))
|
70
|
+
} else {
|
71
|
+
return res
|
72
|
+
}
|
73
|
+
},
|
74
|
+
error => {
|
75
|
+
console.log('err' + error) // for debug
|
76
|
+
Message({
|
77
|
+
message: error.message,
|
78
|
+
type: 'error',
|
79
|
+
duration: 5 * 1000
|
80
|
+
})
|
81
|
+
return Promise.reject(error)
|
82
|
+
}
|
83
|
+
)
|
84
|
+
|
85
|
+
export default service
|
@@ -0,0 +1,58 @@
|
|
1
|
+
Math.easeInOutQuad = function(t, b, c, d) {
|
2
|
+
t /= d / 2
|
3
|
+
if (t < 1) {
|
4
|
+
return c / 2 * t * t + b
|
5
|
+
}
|
6
|
+
t--
|
7
|
+
return -c / 2 * (t * (t - 2) - 1) + b
|
8
|
+
}
|
9
|
+
|
10
|
+
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
|
11
|
+
var requestAnimFrame = (function() {
|
12
|
+
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
|
13
|
+
})()
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Because it's so fucking difficult to detect the scrolling element, just move them all
|
17
|
+
* @param {number} amount
|
18
|
+
*/
|
19
|
+
function move(amount) {
|
20
|
+
document.documentElement.scrollTop = amount
|
21
|
+
document.body.parentNode.scrollTop = amount
|
22
|
+
document.body.scrollTop = amount
|
23
|
+
}
|
24
|
+
|
25
|
+
function position() {
|
26
|
+
return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* @param {number} to
|
31
|
+
* @param {number} duration
|
32
|
+
* @param {Function} callback
|
33
|
+
*/
|
34
|
+
export function scrollTo(to, duration, callback) {
|
35
|
+
const start = position()
|
36
|
+
const change = to - start
|
37
|
+
const increment = 20
|
38
|
+
let currentTime = 0
|
39
|
+
duration = (typeof (duration) === 'undefined') ? 500 : duration
|
40
|
+
var animateScroll = function() {
|
41
|
+
// increment the time
|
42
|
+
currentTime += increment
|
43
|
+
// find the value with the quadratic in-out easing function
|
44
|
+
var val = Math.easeInOutQuad(currentTime, start, change, duration)
|
45
|
+
// move the document.body
|
46
|
+
move(val)
|
47
|
+
// do the animation unless its over
|
48
|
+
if (currentTime < duration) {
|
49
|
+
requestAnimFrame(animateScroll)
|
50
|
+
} else {
|
51
|
+
if (callback && typeof (callback) === 'function') {
|
52
|
+
// the animation is done so lets callback
|
53
|
+
callback()
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
animateScroll()
|
58
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
/**
|
2
|
+
* Created by PanJiaChen on 16/11/18.
|
3
|
+
*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @param {string} path
|
7
|
+
* @returns {Boolean}
|
8
|
+
*/
|
9
|
+
export function isExternal(path) {
|
10
|
+
return /^(https?:|mailto:|tel:)/.test(path)
|
11
|
+
}
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @param {string} str
|
15
|
+
* @returns {Boolean}
|
16
|
+
*/
|
17
|
+
export function validUsername(str) {
|
18
|
+
const valid_map = ['admin', 'editor']
|
19
|
+
return valid_map.indexOf(str.trim()) >= 0
|
20
|
+
}
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @param {string} url
|
24
|
+
* @returns {Boolean}
|
25
|
+
*/
|
26
|
+
export function validURL(url) {
|
27
|
+
const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
|
28
|
+
return reg.test(url)
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* @param {string} str
|
33
|
+
* @returns {Boolean}
|
34
|
+
*/
|
35
|
+
export function validLowerCase(str) {
|
36
|
+
const reg = /^[a-z]+$/
|
37
|
+
return reg.test(str)
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* @param {string} str
|
42
|
+
* @returns {Boolean}
|
43
|
+
*/
|
44
|
+
export function validUpperCase(str) {
|
45
|
+
const reg = /^[A-Z]+$/
|
46
|
+
return reg.test(str)
|
47
|
+
}
|
48
|
+
|
49
|
+
/**
|
50
|
+
* @param {string} str
|
51
|
+
* @returns {Boolean}
|
52
|
+
*/
|
53
|
+
export function validAlphabets(str) {
|
54
|
+
const reg = /^[A-Za-z]+$/
|
55
|
+
return reg.test(str)
|
56
|
+
}
|
57
|
+
|
58
|
+
/**
|
59
|
+
* @param {string} email
|
60
|
+
* @returns {Boolean}
|
61
|
+
*/
|
62
|
+
export function validEmail(email) {
|
63
|
+
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
64
|
+
return reg.test(email)
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
* @param {string} str
|
69
|
+
* @returns {Boolean}
|
70
|
+
*/
|
71
|
+
export function isString(str) {
|
72
|
+
if (typeof str === 'string' || str instanceof String) {
|
73
|
+
return true
|
74
|
+
}
|
75
|
+
return false
|
76
|
+
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* @param {Array} arg
|
80
|
+
* @returns {Boolean}
|
81
|
+
*/
|
82
|
+
export function isArray(arg) {
|
83
|
+
if (typeof Array.isArray === 'undefined') {
|
84
|
+
return Object.prototype.toString.call(arg) === '[object Array]'
|
85
|
+
}
|
86
|
+
return Array.isArray(arg)
|
87
|
+
}
|