diff --git a/.eslintignore b/.eslintignore index 6a5a795..aafc6f2 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,3 +5,4 @@ /*.d.ts /test/unit/coverage/ /node_modules/* +/src/env.d.ts diff --git a/.stylelintignore b/.stylelintignore index 9102993..0ef55ec 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -2,3 +2,4 @@ /public/* public/* /dist* +/src/env.d.ts diff --git a/components.d.ts b/components.d.ts index 675a22d..2b4a381 100644 --- a/components.d.ts +++ b/components.d.ts @@ -5,9 +5,13 @@ declare module 'vue' { export interface GlobalComponents { 404: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Error/404.vue')['default'] + CountTo: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/CountTo/index.vue')['default'] + Echart: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Echart/index.vue')['default'] + ElAlert: typeof import('element-plus/es')['ElAlert'] ElBacktop: typeof import('element-plus/es')['ElBacktop'] ElButton: typeof import('element-plus/es')['ElButton'] ElCard: typeof import('element-plus/es')['ElCard'] + ElCol: typeof import('element-plus/es')['ElCol'] ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] @@ -17,6 +21,7 @@ declare module 'vue' { ElInput: typeof import('element-plus/es')['ElInput'] ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] + ElRow: typeof import('element-plus/es')['ElRow'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSwitch: typeof import('element-plus/es')['ElSwitch'] @@ -25,6 +30,7 @@ declare module 'vue' { ElTooltip: typeof import('element-plus/es')['ElTooltip'] HelloWorld: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/HelloWorld.vue')['default'] ParentView: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/ParentView/index.vue')['default'] + Preview: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Preview/index.vue')['default'] Redirect: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/Redirect/index.vue')['default'] SvgIcon: typeof import('C:/Users/Saber/Documents/HBuilderProjects/vue-element-plus-admin/src/components/SvgIcon/index.vue')['default'] } diff --git a/package.json b/package.json index 28b833f..6369855 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,10 @@ "@element-plus/icons": "^0.0.11", "@vueuse/core": "^6.5.3", "axios": "^0.22.0", + "echarts": "^5.2.1", + "echarts-wordcloud": "^2.0.0", "element-plus": "1.1.0-beta.20", + "intro.js": "^4.2.2", "lodash-es": "^4.17.21", "mockjs": "^1.1.0", "nprogress": "^0.2.0", diff --git a/src/assets/icons/resume.svg b/src/assets/icons/resume.svg new file mode 100644 index 0000000..f37a076 --- /dev/null +++ b/src/assets/icons/resume.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/rotate.svg b/src/assets/icons/rotate.svg index 42ec0e0..d44b4b5 100644 --- a/src/assets/icons/rotate.svg +++ b/src/assets/icons/rotate.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/assets/icons/scale.svg b/src/assets/icons/scale.svg new file mode 100644 index 0000000..bcb2dd9 --- /dev/null +++ b/src/assets/icons/scale.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/unrotate.svg b/src/assets/icons/unrotate.svg new file mode 100644 index 0000000..ba18bfa --- /dev/null +++ b/src/assets/icons/unrotate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/unscale.svg b/src/assets/icons/unscale.svg new file mode 100644 index 0000000..2d84de0 --- /dev/null +++ b/src/assets/icons/unscale.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/CountTo/index.vue b/src/components/CountTo/index.vue new file mode 100644 index 0000000..94bb406 --- /dev/null +++ b/src/components/CountTo/index.vue @@ -0,0 +1,155 @@ + + diff --git a/src/components/CountTo/props.ts b/src/components/CountTo/props.ts new file mode 100644 index 0000000..793c608 --- /dev/null +++ b/src/components/CountTo/props.ts @@ -0,0 +1,62 @@ +import { PropType } from 'vue' +export const countToProps = { + startVal: { + type: Number as PropType, + required: false, + default: 0 + }, + endVal: { + type: Number as PropType, + required: false, + default: 2017 + }, + duration: { + type: Number as PropType, + required: false, + default: 3000 + }, + autoplay: { + type: Boolean as PropType, + required: false, + default: true + }, + decimals: { + type: Number as PropType, + required: false, + default: 0, + validator(value: number) { + return value >= 0 + } + }, + decimal: { + type: String as PropType, + required: false, + default: '.' + }, + separator: { + type: String as PropType, + required: false, + default: ',' + }, + prefix: { + type: String as PropType, + required: false, + default: '' + }, + suffix: { + type: String as PropType, + required: false, + default: '' + }, + useEasing: { + type: Boolean as PropType, + required: false, + default: true + }, + easingFn: { + type: Function as PropType<(t: number, b: number, c: number, d: number) => number>, + default(t: number, b: number, c: number, d: number) { + return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b + } + } +} diff --git a/src/components/Echart/index.vue b/src/components/Echart/index.vue new file mode 100644 index 0000000..0b95e74 --- /dev/null +++ b/src/components/Echart/index.vue @@ -0,0 +1,91 @@ + + + diff --git a/src/components/Preview/index.ts b/src/components/Preview/index.ts new file mode 100644 index 0000000..0294570 --- /dev/null +++ b/src/components/Preview/index.ts @@ -0,0 +1,33 @@ +import ImgPreview from './index.vue' +import { isClient } from '@/utils/validate' + +import type { Options, Props } from './types' + +import { createVNode, render } from 'vue' + +let instance: any = null + +export function createImgPreview(options: Options) { + if (!isClient) return + const { + imageList, + show = true, + index = 0, + onSelect = null, + onClose = null, + zIndex = 500 + } = options + + const propsData: Partial = {} + const container = document.createElement('div') + propsData.imageList = imageList + propsData.show = show + propsData.index = index + propsData.zIndex = zIndex + propsData.onSelect = onSelect + propsData.onClose = onClose + + document.body.appendChild(container) + instance = createVNode(ImgPreview, propsData) + render(instance, container) +} diff --git a/src/components/Preview/index.vue b/src/components/Preview/index.vue new file mode 100644 index 0000000..a104673 --- /dev/null +++ b/src/components/Preview/index.vue @@ -0,0 +1,429 @@ + + + + + diff --git a/src/components/Preview/props.ts b/src/components/Preview/props.ts new file mode 100644 index 0000000..0a2bb67 --- /dev/null +++ b/src/components/Preview/props.ts @@ -0,0 +1,28 @@ +import { PropType } from 'vue' + +export const previewProps = { + index: { + type: Number as PropType, + default: 0 + }, + zIndex: { + type: Number as PropType, + default: 100 + }, + show: { + type: Boolean as PropType, + default: false + }, + imageList: { + type: [Array] as PropType, + default: [] + }, + onClose: { + type: Function as PropType, + default: null + }, + onSelect: { + type: Function as PropType, + default: null + } +} diff --git a/src/components/Preview/types.ts b/src/components/Preview/types.ts new file mode 100644 index 0000000..891d712 --- /dev/null +++ b/src/components/Preview/types.ts @@ -0,0 +1,18 @@ +export interface Options { + show?: boolean + imageList: string[] + index?: number + zIndex?: number + onSelect?: Function | null + onClose?: Function | null +} + +export interface Props { + show: boolean + instance: Props + imageList: string[] + index: number + zIndex: number + onSelect: Function | null + onClose: Function | null +} diff --git a/src/env.d.ts b/src/env.d.ts index a9f088a..d4653f5 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -1,4 +1,4 @@ -// / +/// declare module '*.vue' { import { DefineComponent } from 'vue' diff --git a/src/layout/components/Sider/SiderItem.vue b/src/layout/components/Sider/SiderItem.vue index b882596..8076237 100644 --- a/src/layout/components/Sider/SiderItem.vue +++ b/src/layout/components/Sider/SiderItem.vue @@ -36,7 +36,7 @@ - import { PropType, ref, computed } from 'vue' import type { RouteRecordRaw } from 'vue-router' -import path from 'path-browserify' import { isExternal } from '@/utils/validate' import Item from './Item.vue' import { usePermissionStore } from '@/store/modules/permission' @@ -78,7 +77,6 @@ const props = defineProps({ default: 'Classic' } }) - const onlyOneChild = ref(null) const activeTab = computed(() => permissionStore.getActiveTab) @@ -114,7 +112,10 @@ function resolvePath(routePath: string, otherPath?: string): string { if (isExternal(routePath)) { return routePath } - return path.resolve(otherPath || props.basePath, routePath) + return ( + ((otherPath || props.basePath) === '/' ? '' : otherPath || props.basePath) + + (routePath ? '/' + routePath : '') + ) } diff --git a/src/layout/components/Sider/index.vue b/src/layout/components/Sider/index.vue index f18d03d..79ef21f 100644 --- a/src/layout/components/Sider/index.vue +++ b/src/layout/components/Sider/index.vue @@ -48,9 +48,7 @@ defineProps({ }) const { currentRoute, push } = useRouter() -const routers = computed(() => { - return permissionStore.getRouters -}) +const routers = computed(() => permissionStore.getRouters) const activeMenu = computed(() => { const { meta, path } = currentRoute.value // if set path, the sidebar will highlight the path you set diff --git a/src/plugins/echarts/index.ts b/src/plugins/echarts/index.ts new file mode 100644 index 0000000..54bc668 --- /dev/null +++ b/src/plugins/echarts/index.ts @@ -0,0 +1,33 @@ +import * as echarts from 'echarts/core' + +import { BarChart, LineChart, PieChart, MapChart, PictorialBarChart } from 'echarts/charts' + +import { + TitleComponent, + TooltipComponent, + GridComponent, + PolarComponent, + AriaComponent, + ParallelComponent, + LegendComponent +} from 'echarts/components' + +import { CanvasRenderer } from 'echarts/renderers' + +echarts.use([ + LegendComponent, + TitleComponent, + TooltipComponent, + GridComponent, + PolarComponent, + AriaComponent, + ParallelComponent, + BarChart, + LineChart, + PieChart, + MapChart, + CanvasRenderer, + PictorialBarChart +]) + +export default echarts diff --git a/src/router/index.ts b/src/router/index.ts index 6acad08..377fd79 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -2,11 +2,13 @@ import { createRouter, createWebHashHistory } from 'vue-router' import type { RouteRecordRaw } from 'vue-router' import { AppRouteRecordRaw } from './types' import type { App } from 'vue' -// import { getParentLayout } from './utils' +import { getParentLayout } from './utils' /* Layout */ const Layout = () => import('../layout/index.vue') +// const ParentView = () => import('_c/ParentView/index.vue') + /** * redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击 * name:'router-name' 设定路由的名字,一定要填写不然使用时会出现各种问题 @@ -84,163 +86,163 @@ export const constantRouterMap: AppRouteRecordRaw[] = [ } } ] + }, + { + path: '/external-link', + component: Layout, + meta: {}, + children: [ + { + path: 'http://8.133.179.48:4000/dist-doc/', + meta: { title: '文档', icon: 'documentation' } + } + ] + }, + { + path: '/guide', + component: Layout, + name: 'Guide', + meta: {}, + children: [ + { + path: 'index', + component: () => import('_v/guide/index.vue'), + name: 'GuideDemo', + meta: { + title: '引导页', + icon: 'guide' + } + } + ] } - // { - // path: '/external-link', - // component: Layout, - // meta: {}, - // children: [ - // { - // path: 'http://8.133.179.48:4000/dist-doc/', - // meta: { title: '文档', icon: 'documentation' } - // } - // ] - // }, - // { - // path: '/guide', - // component: Layout, - // name: 'Guide', - // meta: {}, - // children: [ - // { - // path: 'index', - // component: () => import('_v/guide/index.vue'), - // name: 'GuideDemo', - // meta: { - // title: '引导页', - // icon: 'guide' - // } - // } - // ] - // } ] export const asyncRouterMap: AppRouteRecordRaw[] = [ - // { - // path: '/components-demo', - // component: Layout, - // redirect: '/components-demo/echarts', - // name: 'ComponentsDemo', - // meta: { - // title: '功能组件', - // icon: 'component', - // alwaysShow: true - // }, - // children: [ - // { - // path: 'echarts', - // component: () => import('_v/components-demo/echarts/index.vue'), - // name: 'EchartsDemo', - // meta: { - // title: '图表' - // } - // }, - // { - // path: 'preview', - // component: () => import('_v/components-demo/preview/index.vue'), - // name: 'PreviewDemo', - // meta: { - // title: '图片预览' - // } - // }, - // { - // path: 'button', - // component: () => import('_v/components-demo/button/index.vue'), - // name: 'ButtonDemo', - // meta: { - // title: '按钮' - // } - // }, - // { - // path: 'message', - // component: () => import('_v/components-demo/message/index.vue'), - // name: 'MessageDemo', - // meta: { - // title: '消息提示' - // } - // }, - // { - // path: 'count-to', - // component: () => import('_v/components-demo/count-to/index.vue'), - // name: 'CountToDemo', - // meta: { - // title: '数字动画' - // } - // }, - // { - // path: 'search', - // component: () => import('_v/components-demo/search/index.vue'), - // name: 'SearchDemo', - // meta: { - // title: '查询' - // } - // }, - // { - // path: 'editor', - // component: () => import('_v/components-demo/editor/index.vue'), - // name: 'EditorDemo', - // meta: { - // title: '富文本编辑器' - // } - // }, - // { - // path: 'markdown', - // component: () => import('_v/components-demo/markdown/index.vue'), - // name: 'MarkdownDemo', - // meta: { - // title: 'markdown编辑器' - // } - // }, - // { - // path: 'dialog', - // component: () => import('_v/components-demo/dialog/index.vue'), - // name: 'DialogDemo', - // meta: { - // title: '弹窗' - // } - // }, - // { - // path: 'more', - // component: () => import('_v/components-demo/more/index.vue'), - // name: 'MoreDemo', - // meta: { - // title: '显示更多' - // } - // }, - // { - // path: 'detail', - // component: () => import('_v/components-demo/detail/index.vue'), - // name: 'DetailDemo', - // meta: { - // title: '详情组件' - // } - // }, - // { - // path: 'qrcode', - // component: () => import('_v/components-demo/qrcode/index.vue'), - // name: 'QrcodeDemo', - // meta: { - // title: '二维码组件' - // } - // }, - // { - // path: 'avatars', - // component: () => import('_v/components-demo/avatars/index.vue'), - // name: 'AvatarsDemo', - // meta: { - // title: '头像组' - // } - // }, - // { - // path: 'highlight', - // component: () => import('_v/components-demo/highlight/index.vue'), - // name: 'HighlightDemo', - // meta: { - // title: '文字高亮' - // } - // } - // ] - // }, + { + path: '/components-demo', + component: Layout, + redirect: '/components-demo/echarts', + name: 'ComponentsDemo', + meta: { + title: '功能组件', + icon: 'component', + alwaysShow: true + }, + children: [ + { + path: 'echarts', + component: () => import('_v/components-demo/echarts/index.vue'), + name: 'EchartsDemo', + meta: { + title: '图表' + } + }, + { + path: 'preview', + component: () => import('_v/components-demo/preview/index.vue'), + name: 'PreviewDemo', + meta: { + title: '图片预览' + } + } + // { + // path: 'button', + // component: () => import('_v/components-demo/button/index.vue'), + // name: 'ButtonDemo', + // meta: { + // title: '按钮' + // } + // }, + // { + // path: 'message', + // component: () => import('_v/components-demo/message/index.vue'), + // name: 'MessageDemo', + // meta: { + // title: '消息提示' + // } + // }, + // { + // path: 'count-to', + // component: () => import('_v/components-demo/count-to/index.vue'), + // name: 'CountToDemo', + // meta: { + // title: '数字动画' + // } + // }, + // { + // path: 'search', + // component: () => import('_v/components-demo/search/index.vue'), + // name: 'SearchDemo', + // meta: { + // title: '查询' + // } + // }, + // { + // path: 'editor', + // component: () => import('_v/components-demo/editor/index.vue'), + // name: 'EditorDemo', + // meta: { + // title: '富文本编辑器' + // } + // }, + // { + // path: 'markdown', + // component: () => import('_v/components-demo/markdown/index.vue'), + // name: 'MarkdownDemo', + // meta: { + // title: 'markdown编辑器' + // } + // }, + // { + // path: 'dialog', + // component: () => import('_v/components-demo/dialog/index.vue'), + // name: 'DialogDemo', + // meta: { + // title: '弹窗' + // } + // }, + // { + // path: 'more', + // component: () => import('_v/components-demo/more/index.vue'), + // name: 'MoreDemo', + // meta: { + // title: '显示更多' + // } + // }, + // { + // path: 'detail', + // component: () => import('_v/components-demo/detail/index.vue'), + // name: 'DetailDemo', + // meta: { + // title: '详情组件' + // } + // }, + // { + // path: 'qrcode', + // component: () => import('_v/components-demo/qrcode/index.vue'), + // name: 'QrcodeDemo', + // meta: { + // title: '二维码组件' + // } + // }, + // { + // path: 'avatars', + // component: () => import('_v/components-demo/avatars/index.vue'), + // name: 'AvatarsDemo', + // meta: { + // title: '头像组' + // } + // }, + // { + // path: 'highlight', + // component: () => import('_v/components-demo/highlight/index.vue'), + // name: 'HighlightDemo', + // meta: { + // title: '文字高亮' + // } + // } + ] + }, // { // path: '/table-demo', // component: Layout, @@ -481,65 +483,65 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [ // } // ] // }, - // { - // path: '/level', - // component: Layout, - // redirect: '/level/menu1/menu1-1/menu1-1-1', - // name: 'Level', - // meta: { - // title: '多级菜单缓存', - // icon: 'nested' - // }, - // children: [ - // { - // path: 'menu1', - // name: 'Menu1Demo', - // component: getParentLayout('Menu1Demo'), - // redirect: '/level/menu1/menu1-1/menu1-1-1', - // meta: { - // title: 'Menu1' - // }, - // children: [ - // { - // path: 'menu1-1', - // name: 'Menu11Demo', - // component: getParentLayout('Menu11Demo'), - // redirect: '/level/menu1/menu1-1/menu1-1-1', - // meta: { - // title: 'Menu1-1', - // alwaysShow: true - // }, - // children: [ - // { - // path: 'menu1-1-1', - // name: 'Menu111Demo', - // component: () => import('_v/level/Menu111.vue'), - // meta: { - // title: 'Menu1-1-1' - // } - // } - // ] - // }, - // { - // path: 'menu1-2', - // name: 'Menu12Demo', - // component: () => import('_v/level/Menu12.vue'), - // meta: { - // title: 'Menu1-2' - // } - // } - // ] - // }, - // { - // path: 'menu2', - // name: 'Menu2Demo', - // component: () => import('_v/level/Menu2.vue'), - // meta: { - // title: 'Menu2' - // } - // } - // ] - // }, + { + path: '/level', + component: Layout, + redirect: '/level/menu1/menu1-1/menu1-1-1', + name: 'Level', + meta: { + title: '多级菜单缓存', + icon: 'nested' + }, + children: [ + { + path: 'menu1', + name: 'Menu1Demo', + component: getParentLayout('Menu1Demo'), + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: 'Menu1' + }, + children: [ + { + path: 'menu1-1', + name: 'Menu11Demo', + component: getParentLayout('Menu11Demo'), + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: 'Menu1-1', + alwaysShow: true + }, + children: [ + { + path: 'menu1-1-1', + name: 'Menu111Demo', + component: () => import('_v/level/Menu111.vue'), + meta: { + title: 'Menu1-1-1' + } + } + ] + }, + { + path: 'menu1-2', + name: 'Menu12Demo', + component: () => import('_v/level/Menu12.vue'), + meta: { + title: 'Menu1-2' + } + } + ] + }, + { + path: 'menu2', + name: 'Menu2Demo', + component: () => import('_v/level/Menu2.vue'), + meta: { + title: 'Menu2' + } + } + ] + } // { // path: '/example-demo', // component: Layout, diff --git a/src/styles/index.less b/src/styles/index.less index f358c40..ff369ed 100644 --- a/src/styles/index.less +++ b/src/styles/index.less @@ -2,3 +2,4 @@ @import './variables.less'; @import './var.less'; @import './sidebar.less'; +@import './transition.less'; diff --git a/src/styles/sidebar.less b/src/styles/sidebar.less index bbe9363..f0d6270 100644 --- a/src/styles/sidebar.less +++ b/src/styles/sidebar.less @@ -11,7 +11,7 @@ background-color: var(--menu-background-color) !important; .el-menu-item, - .el-submenu__title { + .el-sub-menu__title { color: var(--menu-text-color) !important; background-color: var(--menu-background-color) !important; @@ -20,9 +20,9 @@ } } - .el-submenu { + .el-sub-menu { .el-menu-item, - .el-submenu { + .el-sub-menu { background-color: var(--sub-menu-background-color) !important; } @@ -30,7 +30,7 @@ color: var(--menu-active-text-color) !important; background-color: var(--sub-menu-hover-color) !important; - & > .el-submenu__title { + & > .el-sub-menu__title { color: var(--menu-active-text-color) !important; } } @@ -39,14 +39,14 @@ .el-menu { background-color: var(--sub-menu-background-color) !important; - .el-submenu__title { + .el-sub-menu__title { background-color: var(--sub-menu-background-color) !important; } } } // menu hover .submenu-title-noDropdown, - .el-submenu__title { + .el-sub-menu__title { &:hover { color: var(--sub-menu-active-text-color) !important; background-color: var(--menu-background-color) !important; @@ -67,14 +67,14 @@ background-color: var(--sub-menu-hover-color) !important; } - & > .el-submenu__title { + & > .el-sub-menu__title { color: var(--menu-active-text-color) !important; } } // .nest-menu { // background-color: var(--sub-menu-background-color) !important; - // .el-submenu>.el-submenu__title { + // .el-sub-menu>.el-sub-menu__title { // background-color: var(--sub-menu-background-color) !important; // } // .is-active { @@ -84,14 +84,14 @@ } .el-menu--collapse { - & > div > .el-submenu { + & > div > .el-sub-menu { i { display: none; } } .is-active { - & > .el-submenu__title { + & > .el-sub-menu__title { background-color: var(--sub-menu-hover-color) !important; } } @@ -112,7 +112,7 @@ background-color: var(--menu-background-color) !important; .el-menu-item, - .el-submenu__title { + .el-sub-menu__title { color: var(--menu-text-color) !important; background-color: var(--menu-background-color) !important; @@ -125,7 +125,7 @@ color: var(--menu-active-text-color) !important; background-color: var(--sub-menu-hover-color) !important; - & > .el-submenu__title { + & > .el-sub-menu__title { color: var(--menu-active-text-color) !important; } } @@ -137,7 +137,7 @@ // } // menu hover .submenu-title-noDropdown, - .el-submenu__title { + .el-sub-menu__title { &:hover { color: var(--sub-menu-active-text-color) !important; background-color: var(--menu-background-color) !important; @@ -159,7 +159,7 @@ background-color: var(--top-menu-background-color) !important; .el-menu-item, - .el-submenu__title { + .el-sub-menu__title { height: var(--top-sider-height); line-height: var(--top-sider-height); color: var(--top-menu-text-color) !important; @@ -178,7 +178,7 @@ color: var(--top-menu-active-text-color) !important; background: var(--top-menu-active-background-color) !important; - & > .el-submenu__title { + & > .el-sub-menu__title { color: var(--top-menu-active-text-color) !important; background: var(--top-menu-active-background-color) !important; } @@ -192,7 +192,7 @@ // .nest-menu { // background-color: var(--sub-menu-background-color) !important; - // .el-submenu>.el-submenu__title { + // .el-sub-menu>.el-sub-menu__title { // background-color: var(--sub-menu-background-color) !important; // } // .is-active { @@ -201,7 +201,7 @@ // } // menu hover .submenu-title-noDropdown, - .el-submenu__title { + .el-sub-menu__title { &:hover { color: var(--top-sub-menu-active-text-color) !important; background: var(--top-menu-active-background-color) !important; @@ -217,15 +217,15 @@ } .top-popper-menu { - margin-top: 10px; - margin-left: 10px; + // margin-top: 10px; + // margin-left: 10px; background: var(--top-menu-background-color); .el-menu { background-color: var(--top-menu-background-color) !important; .el-menu-item, - .el-submenu__title { + .el-sub-menu__title { color: var(--top-menu-text-color) !important; background-color: var(--top-menu-background-color) !important; @@ -238,7 +238,7 @@ color: var(--top-menu-active-text-color) !important; background-color: var(--top-menu-active-background-color) !important; - & > .el-submenu__title { + & > .el-sub-menu__title { color: var(--top-menu-active-text-color) !important; background-color: var(--top-menu-active-background-color) !important; @@ -255,7 +255,7 @@ // } // menu hover .submenu-title-noDropdown, - .el-submenu__title { + .el-sub-menu__title { &:hover { color: var(--top-sub-menu-hover-color) !important; background-color: var(--top-menu-background-color) !important; diff --git a/src/utils/dom-uitls.ts b/src/utils/dom-utils.ts similarity index 100% rename from src/utils/dom-uitls.ts rename to src/utils/dom-utils.ts diff --git a/src/utils/validate.ts b/src/utils/validate.ts index c9a9952..31c6c2d 100644 --- a/src/utils/validate.ts +++ b/src/utils/validate.ts @@ -34,7 +34,7 @@ export function isTel(tel: any): boolean { } // 验证数字 -export function isNum(num: any): boolean { +export function isNumber(num: any): boolean { return /^[0-9]*$/.test(num) } @@ -82,3 +82,25 @@ export const isFirefox = function () { export function isString(val: unknown): val is string { return is(val, 'String') } + +export const isWindow = (val: any): val is Window => { + return typeof window !== 'undefined' && is(val, 'Window') +} + +export const isDef = (val?: T): val is T => { + return typeof val !== 'undefined' +} + +export const isUnDef = (val?: T): val is T => { + return !isDef(val) +} + +export const isFunction = (val: unknown): val is Function => typeof val === 'function' + +export const isClient = () => { + return typeof window !== 'undefined' +} + +export const isElement = (val: unknown): val is Element => { + return isObject(val) && !!val.tagName +} diff --git a/src/views/components-demo/echarts/echart-data.ts b/src/views/components-demo/echarts/echart-data.ts new file mode 100644 index 0000000..90282ab --- /dev/null +++ b/src/views/components-demo/echarts/echart-data.ts @@ -0,0 +1,306 @@ +import { EChartsOption } from 'echarts' +import { EChartsOption as EChartsWordOption } from 'echarts-wordcloud' + +export const lineOptions: EChartsOption = { + xAxis: { + data: [ + '一月', + '二月', + '三月', + '四月', + '五月', + '六月', + '七月', + '八月', + '九月', + '十月', + '十一月', + '十二月' + ], + boundaryGap: false, + axisTick: { + show: false + } + }, + grid: { + left: 20, + right: 20, + bottom: 20, + top: 30, + containLabel: true + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross' + }, + padding: [5, 10] + }, + yAxis: { + axisTick: { + show: false + } + }, + legend: { + data: ['预期', '实际'] + }, + series: [ + { + name: '预期', + smooth: true, + type: 'line', + data: [100, 120, 161, 134, 105, 160, 165, 114, 163, 185, 118, 123], + animationDuration: 2800, + animationEasing: 'cubicInOut' + }, + { + name: '实际', + smooth: true, + type: 'line', + itemStyle: {}, + data: [120, 82, 91, 154, 162, 140, 145, 250, 134, 56, 99, 123], + animationDuration: 2800, + animationEasing: 'quadraticOut' + } + ] +} + +export const pieOptions: EChartsOption = { + title: { + text: '用户访问来源', + left: 'center' + }, + tooltip: { + trigger: 'item', + formatter: '{a}
{b} : {c} ({d}%)' + }, + legend: { + orient: 'vertical', + left: 'left', + data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'] + }, + series: [ + { + name: '用户访问来源', + type: 'pie', + radius: '55%', + center: ['50%', '60%'], + data: [ + { value: 335, name: '直接访问' }, + { value: 310, name: '邮件营销' }, + { value: 234, name: '联盟广告' }, + { value: 135, name: '视频广告' }, + { value: 1548, name: '搜索引擎' } + ] + } + ] +} + +export const barOptions: EChartsOption = { + title: { + text: '每周用户活跃量', + left: 'center' + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + xAxis: { + type: 'category', + data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], + axisTick: { + alignWithLabel: true + } + }, + yAxis: { + type: 'value' + }, + series: [ + { + name: '活跃量', + data: [13253, 34235, 26321, 12340, 24643, 1322, 1324], + type: 'bar' + } + ] +} + +export const pieOptions2: EChartsOption = { + title: { + text: '用户访问来源', + left: 'center' + }, + tooltip: { + trigger: 'item', + formatter: '{a}
{b} : {c} ({d}%)' + }, + legend: { + orient: 'vertical', + left: 'left' + }, + series: [ + { + name: '访问来源', + type: 'pie', + radius: '55%', + center: ['50%', '50%'], + data: [ + { + value: 335, + name: '直接访问' + }, + { + value: 310, + name: '邮件营销' + }, + { + value: 274, + name: '联盟广告' + }, + { + value: 235, + name: '视频广告' + }, + { + value: 400, + name: '搜索引擎' + } + ].sort(function (a, b) { + return a.value - b.value + }), + emphasis: { + itemStyle: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + } + ] +} + +export const wordOptions: EChartsWordOption = { + tooltip: {}, + series: [ + { + type: 'wordCloud', + gridSize: 2, + sizeRange: [12, 50], + rotationRange: [-90, 90], + shape: 'pentagon', + width: 600, + height: 400, + drawOutOfBound: true, + textStyle: { + color: function () { + return ( + 'rgb(' + + [ + Math.round(Math.random() * 160), + Math.round(Math.random() * 160), + Math.round(Math.random() * 160) + ].join(',') + + ')' + ) + } + }, + emphasis: { + textStyle: { + shadowBlur: 10, + shadowColor: '#333' + } + }, + data: [ + { + name: 'Sam S Club', + value: 10000, + textStyle: { + color: 'black' + }, + emphasis: { + textStyle: { + color: 'red' + } + } + }, + { + name: 'Macys', + value: 6181 + }, + { + name: 'Amy Schumer', + value: 4386 + }, + { + name: 'Jurassic World', + value: 4055 + }, + { + name: 'Charter Communications', + value: 2467 + }, + { + name: 'Chick Fil A', + value: 2244 + }, + { + name: 'Planet Fitness', + value: 1898 + }, + { + name: 'Pitch Perfect', + value: 1484 + }, + { + name: 'Express', + value: 1112 + }, + { + name: 'Home', + value: 965 + }, + { + name: 'Johnny Depp', + value: 847 + }, + { + name: 'Lena Dunham', + value: 582 + }, + { + name: 'Lewis Hamilton', + value: 555 + }, + { + name: 'KXAN', + value: 550 + }, + { + name: 'Mary Ellen Mark', + value: 462 + }, + { + name: 'Farrah Abraham', + value: 366 + }, + { + name: 'Rita Ora', + value: 360 + }, + { + name: 'Serena Williams', + value: 282 + }, + { + name: 'NCAA baseball tournament', + value: 273 + }, + { + name: 'Point Break', + value: 265 + } + ] + } + ] +} diff --git a/src/views/components-demo/echarts/index.vue b/src/views/components-demo/echarts/index.vue new file mode 100644 index 0000000..a6f404e --- /dev/null +++ b/src/views/components-demo/echarts/index.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/src/views/components-demo/preview/index.vue b/src/views/components-demo/preview/index.vue new file mode 100644 index 0000000..bae6649 --- /dev/null +++ b/src/views/components-demo/preview/index.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/src/views/dashboard/components/PanelGroup.vue b/src/views/dashboard/components/PanelGroup.vue new file mode 100644 index 0000000..51f89a9 --- /dev/null +++ b/src/views/dashboard/components/PanelGroup.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/src/views/dashboard/echart-data.ts b/src/views/dashboard/echart-data.ts new file mode 100644 index 0000000..2aff8f8 --- /dev/null +++ b/src/views/dashboard/echart-data.ts @@ -0,0 +1,126 @@ +import { EChartsOption } from 'echarts' + +export const lineOptions: EChartsOption = { + xAxis: { + data: [ + '一月', + '二月', + '三月', + '四月', + '五月', + '六月', + '七月', + '八月', + '九月', + '十月', + '十一月', + '十二月' + ], + boundaryGap: false, + axisTick: { + show: false + } + }, + grid: { + left: 20, + right: 20, + bottom: 20, + top: 30, + containLabel: true + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross' + }, + padding: [5, 10] + }, + yAxis: { + axisTick: { + show: false + } + }, + legend: { + data: ['预期', '实际'] + }, + series: [ + { + name: '预期', + smooth: true, + type: 'line', + data: [100, 120, 161, 134, 105, 160, 165, 114, 163, 185, 118, 123], + animationDuration: 2800, + animationEasing: 'cubicInOut' + }, + { + name: '实际', + smooth: true, + type: 'line', + itemStyle: {}, + data: [120, 82, 91, 154, 162, 140, 145, 250, 134, 56, 99, 123], + animationDuration: 2800, + animationEasing: 'quadraticOut' + } + ] +} + +export const pieOptions: EChartsOption = { + title: { + text: '用户访问来源', + left: 'center' + }, + tooltip: { + trigger: 'item', + formatter: '{a}
{b} : {c} ({d}%)' + }, + legend: { + orient: 'vertical', + left: 'left', + data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'] + }, + series: [ + { + name: '用户访问来源', + type: 'pie', + radius: '55%', + center: ['50%', '60%'], + data: [ + { value: 335, name: '直接访问' }, + { value: 310, name: '邮件营销' }, + { value: 234, name: '联盟广告' }, + { value: 135, name: '视频广告' }, + { value: 1548, name: '搜索引擎' } + ] + } + ] +} + +export const barOptions: EChartsOption = { + title: { + text: '每周用户活跃量', + left: 'center' + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + xAxis: { + type: 'category', + data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], + axisTick: { + alignWithLabel: true + } + }, + yAxis: { + type: 'value' + }, + series: [ + { + name: '活跃量', + data: [13253, 34235, 26321, 12340, 24643, 1322, 1324], + type: 'bar' + } + ] +} diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue index 3db4d08..72fa249 100644 --- a/src/views/dashboard/index.vue +++ b/src/views/dashboard/index.vue @@ -1,5 +1,35 @@ - + + + diff --git a/src/views/guide/index.vue b/src/views/guide/index.vue new file mode 100644 index 0000000..90a4465 --- /dev/null +++ b/src/views/guide/index.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/views/guide/steps.ts b/src/views/guide/steps.ts new file mode 100644 index 0000000..718bcd0 --- /dev/null +++ b/src/views/guide/steps.ts @@ -0,0 +1,40 @@ +const steps = [ + { + element: '#sidebar__wrap', + title: '菜单栏', + intro: '以路由的结构渲染的菜单栏', + position: 'right' + }, + { + element: '#hamburger-container', + title: '展开缩收', + intro: '用于展开和缩放菜单栏', + position: 'bottom' + }, + { + element: '#breadcrumb-container', + title: '面包屑', + intro: '用于记录当前路由结构', + position: 'bottom' + }, + { + element: '#screenfull-container', + title: '是否全屏', + intro: '用于设置是否全屏', + position: 'bottom' + }, + { + element: '#user-container', + title: '用户信息', + intro: '用于展示用户', + position: 'bottom' + }, + { + element: '#tag-container', + title: '标签页', + intro: '用于记录路由历史记录', + position: 'bottom' + } +] + +export default steps diff --git a/src/views/level/menu111.vue b/src/views/level/menu111.vue new file mode 100644 index 0000000..34a9dc8 --- /dev/null +++ b/src/views/level/menu111.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/views/level/menu12.vue b/src/views/level/menu12.vue new file mode 100644 index 0000000..f27ca07 --- /dev/null +++ b/src/views/level/menu12.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/views/level/menu2.vue b/src/views/level/menu2.vue new file mode 100644 index 0000000..30c8eb2 --- /dev/null +++ b/src/views/level/menu2.vue @@ -0,0 +1,12 @@ + + + diff --git a/yarn.lock b/yarn.lock index 8a928f4..2032aed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2478,6 +2478,19 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" +echarts-wordcloud@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/echarts-wordcloud/-/echarts-wordcloud-2.0.0.tgz#52ef817895801ffe9e99dd1bacab7686b2dec04a" + integrity sha512-K7l6pTklqdW7ZWzT/1CS0KhBSINr/cd7c5N1fVMzZMwLQHEwT7x+nivK7g5hkVh7WNcAv4Dn6/ZS5zMKRozC1g== + +echarts@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.2.1.tgz#bd58ec011cd82def4a714e4038ef4b73b8417bc3" + integrity sha512-OJ79b22eqRfbSV8vYmDKmA+XWfNbr0Uk/OafWcFNIGDWti2Uw9A6eVCiJLmqPa9Sk+EWL+t5v26aak0z3gxiZw== + dependencies: + tslib "2.3.0" + zrender "5.2.1" + electron-to-chromium@^1.3.857: version "1.3.864" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz#6a993bcc196a2b8b3df84d28d5d4dd912393885f" @@ -3661,6 +3674,11 @@ inquirer@6.5.2: strip-ansi "^5.1.0" through "^2.3.6" +intro.js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/intro.js/-/intro.js-4.2.2.tgz#9077549cc6ef697e78d18d1c05003b7471281e1a" + integrity sha512-Zgz2e8syCuttJ2vJlDOWCSWPUJBr7AOJkU5Ti3zcvXho+y//q0ixwoT+PkPLJWI7AX35IdgRcxAEWUrOAJYiNQ== + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.nlark.com/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -6774,6 +6792,11 @@ ts-node@^9: source-map-support "^0.5.17" yn "3.1.1" +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -7459,6 +7482,13 @@ yocto-queue@^0.1.0: resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +zrender@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.2.1.tgz#5f4bbda915ba6d412b0b19dc2431beaad05417bb" + integrity sha512-M3bPGZuyLTNBC6LiNKXJwSCtglMp8XUEqEBG+2MdICDI3d1s500Y4P0CzldQGsqpRVB7fkvf3BKQQRxsEaTlsw== + dependencies: + tslib "2.3.0" + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"