diff --git a/auto-imports.d.ts b/auto-imports.d.ts
new file mode 100644
index 0000000..24e619c
--- /dev/null
+++ b/auto-imports.d.ts
@@ -0,0 +1,6 @@
+// Generated by 'unplugin-auto-import'
+export {}
+declare global {
+ const ElMessage: typeof import('element-plus/es')['ElMessage']
+ const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
+}
diff --git a/components.d.ts b/components.d.ts
new file mode 100644
index 0000000..1f77b3f
--- /dev/null
+++ b/components.d.ts
@@ -0,0 +1,69 @@
+// generated by unplugin-vue-components
+// We suggest you to commit this file into source control
+// Read more: https://github.com/vuejs/core/pull/3399
+import '@vue/runtime-core'
+
+export {}
+
+declare module '@vue/runtime-core' {
+ export interface GlobalComponents {
+ Breadcrumb: typeof import('./src/components/Breadcrumb/index.vue')['default']
+ DropdownMenu: typeof import('./src/components/Share/DropdownMenu.vue')['default']
+ ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
+ ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
+ ElButton: typeof import('element-plus/es')['ElButton']
+ ElCard: typeof import('element-plus/es')['ElCard']
+ ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
+ ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
+ ElCol: typeof import('element-plus/es')['ElCol']
+ ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
+ ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+ ElDialog: typeof import('element-plus/es')['ElDialog']
+ ElDropdown: typeof import('element-plus/es')['ElDropdown']
+ ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
+ ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
+ ElForm: typeof import('element-plus/es')['ElForm']
+ ElFormItem: typeof import('element-plus/es')['ElFormItem']
+ ElIcon: typeof import('element-plus/es')['ElIcon']
+ ElInput: typeof import('element-plus/es')['ElInput']
+ ElMenu: typeof import('element-plus/es')['ElMenu']
+ ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+ ElOption: typeof import('element-plus/es')['ElOption']
+ ElPagination: typeof import('element-plus/es')['ElPagination']
+ ElProgress: typeof import('element-plus/es')['ElProgress']
+ ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
+ ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
+ ElRate: typeof import('element-plus/es')['ElRate']
+ ElRow: typeof import('element-plus/es')['ElRow']
+ ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
+ ElSelect: typeof import('element-plus/es')['ElSelect']
+ ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
+ ElSwitch: typeof import('element-plus/es')['ElSwitch']
+ ElTable: typeof import('element-plus/es')['ElTable']
+ ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+ ElTabPane: typeof import('element-plus/es')['ElTabPane']
+ ElTabs: typeof import('element-plus/es')['ElTabs']
+ ElTag: typeof import('element-plus/es')['ElTag']
+ ElTooltip: typeof import('element-plus/es')['ElTooltip']
+ ElTree: typeof import('element-plus/es')['ElTree']
+ GithubCorner: typeof import('./src/components/GithubCorner/index.vue')['default']
+ Hamburger: typeof import('./src/components/Hamburger/index.vue')['default']
+ HeaderSearch: typeof import('./src/components/HeaderSearch/index.vue')['default']
+ Keyboard: typeof import('./src/components/Charts/Keyboard.vue')['default']
+ LineMarker: typeof import('./src/components/Charts/LineMarker.vue')['default']
+ Mallki: typeof import('./src/components/TextHoverEffect/Mallki.vue')['default']
+ MixChart: typeof import('./src/components/Charts/MixChart.vue')['default']
+ Pagination: typeof import('./src/components/Pagination/index.vue')['default']
+ PanThumb: typeof import('./src/components/PanThumb/index.vue')['default']
+ RightPanel: typeof import('./src/components/RightPanel/index.vue')['default']
+ RouterLink: typeof import('vue-router')['RouterLink']
+ RouterView: typeof import('vue-router')['RouterView']
+ Screenfull: typeof import('./src/components/Screenfull/index.vue')['default']
+ SizeSelect: typeof import('./src/components/SizeSelect/index.vue')['default']
+ SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
+ VueCountTo: typeof import('./src/components/vue-count-to/vue-countTo.vue')['default']
+ }
+ export interface ComponentCustomProperties {
+ vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+ }
+}
diff --git a/mock/demo/_routes.js b/mock/demo/_routes.js
index 2ee4fa3..faa10c9 100644
--- a/mock/demo/_routes.js
+++ b/mock/demo/_routes.js
@@ -4,7 +4,9 @@ export const constantRoutes = [
{
path: '/redirect',
component: 'layout/Layout',
- hidden: true,
+ meta: {
+ hidden: true
+ },
children: [
{
path: '/redirect/:path*',
@@ -15,22 +17,30 @@ export const constantRoutes = [
{
path: '/login',
component: 'views/login/index',
- hidden: true
+ meta: {
+ hidden: true
+ }
},
{
path: '/auth-redirect',
component: 'views/login/auth-redirect',
- hidden: true
+ meta: {
+ hidden: true
+ }
},
{
path: '/404',
component: 'views/error-page/404',
- hidden: true
+ meta: {
+ hidden: true
+ }
},
{
path: '/401',
component: 'views/error-page/401',
- hidden: true
+ meta: {
+ hidden: true
+ }
},
{
path: '',
@@ -77,8 +87,8 @@ export const asyncRoutes = [
path: '/permission',
component: 'layout/Layout',
redirect: '/permission/index',
- alwaysShow: true,
meta: {
+ alwaysShow: true,
title: 'Permission',
icon: 'lock',
roles: ['admin', 'editor']
@@ -333,8 +343,7 @@ export const asyncRoutes = [
path: 'edit/:id(\\d+)',
component: 'views/example/edit',
name: 'EditArticle',
- meta: { title: 'Edit Article', noCache: true },
- hidden: true
+ meta: { hidden: true, title: 'Edit Article', noCache: true }
},
{
path: 'list',
@@ -438,8 +447,7 @@ export const asyncRoutes = [
path: '/zip',
component: 'layout/Layout',
redirect: '/zip/download',
- alwaysShow: true,
- meta: { title: 'Zip', icon: 'zip' },
+ meta: { alwaysShow: true, title: 'Zip', icon: 'zip' },
children: [
{
path: 'download',
@@ -466,7 +474,9 @@ export const asyncRoutes = [
{
path: '/pdf/download',
component: 'views/pdf/download',
- hidden: true
+ meta: {
+ hidden: true
+ }
},
{
@@ -521,5 +531,5 @@ export const asyncRoutes = [
]
},
- { path: '*', redirect: '/404', hidden: true }
+ { path: '*', redirect: '/404', meta: { hidden: true }}
];
diff --git a/package-lock.json b/package-lock.json
index 3983ddf..ce9e585 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5901,6 +5901,11 @@
}
}
},
+ "sortablejs": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.15.0.tgz",
+ "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
+ },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
diff --git a/package.json b/package.json
index 2baa816..a130df0 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"path-to-regexp": "6.2.1",
"pinia": "2.0.28",
"sass": "1.56.2",
+ "sortablejs": "1.15.0",
"vue": "3.2.45",
"vue-router": "4.1.6"
},
diff --git a/src/api/user.js b/src/api/user.js
index 02fcacc..37bc37f 100644
--- a/src/api/user.js
+++ b/src/api/user.js
@@ -16,9 +16,10 @@ export function getInfo(token) {
});
}
-export function logout() {
+export function logout(token) {
return request({
url: '/vue-element-admin/user/logout',
- method: 'post'
+ method: 'post',
+ params: { token }
});
}
diff --git a/src/components/Charts/Keyboard.vue b/src/components/Charts/Keyboard.vue
new file mode 100644
index 0000000..ad56e43
--- /dev/null
+++ b/src/components/Charts/Keyboard.vue
@@ -0,0 +1,148 @@
+
+
+
+
+
diff --git a/src/components/Charts/LineMarker.vue b/src/components/Charts/LineMarker.vue
new file mode 100644
index 0000000..a1f2d10
--- /dev/null
+++ b/src/components/Charts/LineMarker.vue
@@ -0,0 +1,208 @@
+
+
+
+
+
diff --git a/src/components/Charts/MixChart.vue b/src/components/Charts/MixChart.vue
new file mode 100644
index 0000000..262f6f6
--- /dev/null
+++ b/src/components/Charts/MixChart.vue
@@ -0,0 +1,266 @@
+
+
+
+
+
diff --git a/src/components/Charts/mixins/resize.js b/src/components/Charts/mixins/resize.js
new file mode 100644
index 0000000..d8ca5f0
--- /dev/null
+++ b/src/components/Charts/mixins/resize.js
@@ -0,0 +1,56 @@
+import { debounce } from '@/utils';
+
+export default {
+ data() {
+ return {
+ $_sidebarElm: null,
+ $_resizeHandler: null
+ };
+ },
+ mounted() {
+ this.initListener();
+ },
+ activated() {
+ if (!this.$_resizeHandler) {
+ // avoid duplication init
+ this.initListener();
+ }
+
+ // when keep-alive chart activated, auto resize
+ this.resize();
+ },
+ beforeDestroy() {
+ this.destroyListener();
+ },
+ deactivated() {
+ this.destroyListener();
+ },
+ methods: {
+ // use $_ for mixins properties
+ // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+ $_sidebarResizeHandler(e) {
+ if (e.propertyName === 'width') {
+ this.$_resizeHandler();
+ }
+ },
+ initListener() {
+ this.$_resizeHandler = debounce(() => {
+ this.resize();
+ }, 100);
+ window.addEventListener('resize', this.$_resizeHandler);
+
+ this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0];
+ this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler);
+ },
+ destroyListener() {
+ window.removeEventListener('resize', this.$_resizeHandler);
+ this.$_resizeHandler = null;
+
+ this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler);
+ },
+ resize() {
+ const { chart } = this;
+ chart && chart.resize();
+ }
+ }
+};
diff --git a/src/components/HeaderSearch/index.vue b/src/components/HeaderSearch/index.vue
index 4caa36b..3d22ee0 100644
--- a/src/components/HeaderSearch/index.vue
+++ b/src/components/HeaderSearch/index.vue
@@ -95,7 +95,7 @@ export default defineComponent({
for (const router of routes) {
// skip hidden router
- if (router.hidden) { continue; }
+ if (router.meta && router.meta.hidden) { continue; }
const data = {
path: path.resolve(basePath, router.path),
diff --git a/src/components/Pagination/index.vue b/src/components/Pagination/index.vue
new file mode 100644
index 0000000..b97e17d
--- /dev/null
+++ b/src/components/Pagination/index.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
diff --git a/src/directive/waves/index.js b/src/directive/waves/index.js
new file mode 100644
index 0000000..c38d799
--- /dev/null
+++ b/src/directive/waves/index.js
@@ -0,0 +1,13 @@
+import waves from './waves';
+
+const install = function(Vue) {
+ Vue.directive('waves', waves);
+};
+
+if (window.Vue) {
+ window.waves = waves;
+ Vue.use(install); // eslint-disable-line
+}
+
+waves.install = install;
+export default waves;
diff --git a/src/directive/waves/waves.css b/src/directive/waves/waves.css
new file mode 100644
index 0000000..af7a7ef
--- /dev/null
+++ b/src/directive/waves/waves.css
@@ -0,0 +1,26 @@
+.waves-ripple {
+ position: absolute;
+ border-radius: 100%;
+ background-color: rgba(0, 0, 0, 0.15);
+ background-clip: padding-box;
+ pointer-events: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-transform: scale(0);
+ -ms-transform: scale(0);
+ transform: scale(0);
+ opacity: 1;
+}
+
+.waves-ripple.z-active {
+ opacity: 0;
+ -webkit-transform: scale(2);
+ -ms-transform: scale(2);
+ transform: scale(2);
+ -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+ transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+ transition: opacity 1.2s ease-out, transform 0.6s ease-out;
+ transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
+}
\ No newline at end of file
diff --git a/src/directive/waves/waves.js b/src/directive/waves/waves.js
new file mode 100644
index 0000000..fc32338
--- /dev/null
+++ b/src/directive/waves/waves.js
@@ -0,0 +1,72 @@
+import './waves.css';
+
+const context = '@@wavesContext';
+
+function handleClick(el, binding) {
+ function handle(e) {
+ const customOpts = Object.assign({}, binding.value);
+ const opts = Object.assign({
+ ele: el, // 波纹作用元素
+ type: 'hit', // hit 点击位置扩散 center中心点扩展
+ color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
+ },
+ customOpts
+ );
+ const target = opts.ele;
+ if (target) {
+ target.style.position = 'relative';
+ target.style.overflow = 'hidden';
+ const rect = target.getBoundingClientRect();
+ let ripple = target.querySelector('.waves-ripple');
+ if (!ripple) {
+ ripple = document.createElement('span');
+ ripple.className = 'waves-ripple';
+ ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
+ target.appendChild(ripple);
+ } else {
+ ripple.className = 'waves-ripple';
+ }
+ switch (opts.type) {
+ case 'center':
+ ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px';
+ ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px';
+ break;
+ default:
+ ripple.style.top =
+ (e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
+ document.body.scrollTop) + 'px';
+ ripple.style.left =
+ (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
+ document.body.scrollLeft) + 'px';
+ }
+ ripple.style.backgroundColor = opts.color;
+ ripple.className = 'waves-ripple z-active';
+ return false;
+ }
+ }
+
+ if (!el[context]) {
+ el[context] = {
+ removeHandle: handle
+ };
+ } else {
+ el[context].removeHandle = handle;
+ }
+
+ return handle;
+}
+
+export default {
+ bind(el, binding) {
+ el.addEventListener('click', handleClick(el, binding), false);
+ },
+ update(el, binding) {
+ el.removeEventListener('click', el[context].removeHandle, false);
+ el.addEventListener('click', handleClick(el, binding), false);
+ },
+ unbind(el) {
+ el.removeEventListener('click', el[context].removeHandle, false);
+ el[context] = null;
+ delete el[context];
+ }
+};
diff --git a/src/layout/components/Sidebar/Item.vue b/src/layout/components/Sidebar/Item.vue
deleted file mode 100644
index 62c08ce..0000000
--- a/src/layout/components/Sidebar/Item.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
diff --git a/src/layout/components/Sidebar/SidebarItem.vue b/src/layout/components/Sidebar/SidebarItem.vue
index 437b815..875f059 100644
--- a/src/layout/components/Sidebar/SidebarItem.vue
+++ b/src/layout/components/Sidebar/SidebarItem.vue
@@ -1,7 +1,7 @@
-