mirror of
https://gitee.com/log4j/pig-ui.git
synced 2024-12-31 09:12:10 +08:00
'admin-20.12.31:完成主体布局、添加切换专场动画等'
This commit is contained in:
parent
1ccc74ec2b
commit
c482f693fe
@ -1,5 +1,5 @@
|
||||
# port 端口号
|
||||
VITE_PORT = 8080
|
||||
VITE_PORT = 9000
|
||||
|
||||
# open 运行 npm run dev 时自动打开浏览器
|
||||
VITE_OPEN = false
|
||||
|
@ -1,22 +1,23 @@
|
||||
import dotenv from 'dotenv';
|
||||
// vite 打包相关
|
||||
import dotenv from 'dotenv'
|
||||
export interface ViteEnv {
|
||||
VITE_PORT: number;
|
||||
VITE_OPEN: boolean;
|
||||
VITE_PUBLIC_PATH: string;
|
||||
VITE_PORT: number
|
||||
VITE_OPEN: boolean
|
||||
VITE_PUBLIC_PATH: string
|
||||
}
|
||||
|
||||
export function loadEnv(): ViteEnv {
|
||||
const env = process.env.NODE_ENV;
|
||||
const ret: any = {};
|
||||
const env = process.env.NODE_ENV
|
||||
const ret: any = {}
|
||||
const envList = [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env', ,]
|
||||
envList.forEach((e) => { dotenv.config({ path: e }) });
|
||||
envList.forEach((e) => { dotenv.config({ path: e }) })
|
||||
for (const envName of Object.keys(process.env)) {
|
||||
let realName = (process.env as any)[envName].replace(/\\n/g, '\n');
|
||||
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
|
||||
if (envName === 'VITE_PORT') realName = Number(realName);
|
||||
if (envName === 'VITE_OPEN') realName = Boolean(realName);
|
||||
ret[envName] = realName;
|
||||
process.env[envName] = realName;
|
||||
let realName = (process.env as any)[envName].replace(/\\n/g, '\n')
|
||||
realName = realName === 'true' ? true : realName === 'false' ? false : realName
|
||||
if (envName === 'VITE_PORT') realName = Number(realName)
|
||||
if (envName === 'VITE_OPEN') realName = Boolean(realName)
|
||||
ret[envName] = realName
|
||||
process.env[envName] = realName
|
||||
}
|
||||
return ret;
|
||||
return ret
|
||||
}
|
@ -6,11 +6,13 @@
|
||||
"build": "vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"element-plus": "^v1.0.1-beta.14",
|
||||
"element-plus": "^v1.0.1-beta.17",
|
||||
"sortablejs": "^1.10.2",
|
||||
"vue": "^3.0.4",
|
||||
"vue-router": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/sortablejs": "^1.10.6",
|
||||
"@vue/compiler-sfc": "^3.0.4",
|
||||
"sass": "^1.30.0",
|
||||
"sass-loader": "^10.1.0",
|
||||
|
@ -1,3 +1,16 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { onBeforeMount } from "vue";
|
||||
import { setIconfont } from "/@/utils/setIconfont.ts";
|
||||
export default {
|
||||
name: "app",
|
||||
setup() {
|
||||
onBeforeMount(() => {
|
||||
setIconfont(["//at.alicdn.com/t/font_2298093_8wsrw2zw3rg.css"]);
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,3 +0,0 @@
|
||||
<template>
|
||||
dd
|
||||
</template>
|
@ -7,14 +7,169 @@ const staticRoutes: Array<RouteRecordRaw> = [
|
||||
component: () => import('/@/views/layout/index.vue'),
|
||||
redirect: '/home',
|
||||
meta: {
|
||||
title: '首页'
|
||||
title: '首页',
|
||||
index: 0
|
||||
},
|
||||
children: [{
|
||||
path: '/home',
|
||||
name: 'home',
|
||||
component: () => import('/@/views/home/index.vue'),
|
||||
meta: {
|
||||
title: '首页'
|
||||
title: '首页',
|
||||
index: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs',
|
||||
name: 'docs',
|
||||
component: () => import('/@/views/docs/index.vue'),
|
||||
meta: {
|
||||
title: '文档',
|
||||
index: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs1',
|
||||
name: 'docs1',
|
||||
component: () => import('/@/views/docs copy 1/index.vue'),
|
||||
meta: {
|
||||
title: '文档1',
|
||||
index: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs2',
|
||||
name: 'docs2',
|
||||
component: () => import('/@/views/docs copy 2/index.vue'),
|
||||
meta: {
|
||||
title: '文档2',
|
||||
index: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs3',
|
||||
name: 'docs3',
|
||||
component: () => import('/@/views/docs copy 3/index.vue'),
|
||||
meta: {
|
||||
title: '文档3',
|
||||
index: 4
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs4',
|
||||
name: 'docs4',
|
||||
component: () => import('/@/views/docs copy 4/index.vue'),
|
||||
meta: {
|
||||
title: '文档4',
|
||||
index: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs5',
|
||||
name: 'docs5',
|
||||
component: () => import('/@/views/docs copy 5/index.vue'),
|
||||
meta: {
|
||||
title: '文档5',
|
||||
index: 6
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs6',
|
||||
name: 'docs6',
|
||||
component: () => import('/@/views/docs copy 6/index.vue'),
|
||||
meta: {
|
||||
title: '文档6',
|
||||
index: 7
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs7',
|
||||
name: 'docs7',
|
||||
component: () => import('/@/views/docs copy 7/index.vue'),
|
||||
meta: {
|
||||
title: '文档7',
|
||||
index: 8
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs8',
|
||||
name: 'docs8',
|
||||
component: () => import('/@/views/docs copy 8/index.vue'),
|
||||
meta: {
|
||||
title: '文档8',
|
||||
index: 9
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs9',
|
||||
name: 'docs9',
|
||||
component: () => import('/@/views/docs copy 9/index.vue'),
|
||||
meta: {
|
||||
title: '文档9',
|
||||
index: 10
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs10',
|
||||
name: 'docs10',
|
||||
component: () => import('/@/views/docs copy 10/index.vue'),
|
||||
meta: {
|
||||
title: '文档10',
|
||||
index: 11
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs11',
|
||||
name: 'docs11',
|
||||
component: () => import('/@/views/docs copy 11/index.vue'),
|
||||
meta: {
|
||||
title: '文档11',
|
||||
index: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs12',
|
||||
name: 'docs12',
|
||||
component: () => import('/@/views/docs copy 12/index.vue'),
|
||||
meta: {
|
||||
title: '文档12',
|
||||
index: 13
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs13',
|
||||
name: 'docs13',
|
||||
component: () => import('/@/views/docs copy 13/index.vue'),
|
||||
meta: {
|
||||
title: '文档13',
|
||||
index: 14
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs14',
|
||||
name: 'docs14',
|
||||
component: () => import('/@/views/docs copy 14/index.vue'),
|
||||
meta: {
|
||||
title: '文档14',
|
||||
index: 15
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs15',
|
||||
name: 'docs15',
|
||||
component: () => import('/@/views/docs copy 15/index.vue'),
|
||||
meta: {
|
||||
title: '文档15',
|
||||
index: 16
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/docs16',
|
||||
name: 'docs16',
|
||||
component: () => import('/@/views/docs copy 16/index.vue'),
|
||||
meta: {
|
||||
title: '文档16',
|
||||
index: 17
|
||||
}
|
||||
}]
|
||||
},
|
||||
@ -26,9 +181,25 @@ const staticRoutes: Array<RouteRecordRaw> = [
|
||||
title: '登陆'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
name: '404',
|
||||
component: () => import('/@/views/error/404.vue'),
|
||||
meta: {
|
||||
title: '找不到此页面'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/401',
|
||||
name: '401',
|
||||
component: () => import('/@/views/error/401.vue'),
|
||||
meta: {
|
||||
title: '没有权限'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)',
|
||||
redirect: '/'
|
||||
redirect: '/404'
|
||||
}
|
||||
]
|
||||
|
||||
@ -37,4 +208,8 @@ const router = createRouter({
|
||||
routes: staticRoutes
|
||||
})
|
||||
|
||||
// router.afterEach((to, from) => {
|
||||
|
||||
// })
|
||||
|
||||
export default router
|
@ -1,3 +1,5 @@
|
||||
/* 初始化样式
|
||||
------------------------------- */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@ -9,20 +11,68 @@ body,
|
||||
#app {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
|
||||
Microsoft YaHei, SimSun, sans-serif;
|
||||
font-weight: 400;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background-color: #f8f8f8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 主布局样式
|
||||
------------------------------- */
|
||||
.layout-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.el-aside {
|
||||
background: #29384d;
|
||||
border-right: 1px solid rgb(230, 230, 230);
|
||||
height: inherit;
|
||||
}
|
||||
.el-header {
|
||||
box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
|
||||
padding: 0 !important;
|
||||
}
|
||||
.el-main {
|
||||
padding: 0 !important;
|
||||
overflow: unset !important;
|
||||
}
|
||||
.el-scrollbar {
|
||||
width: 100%;
|
||||
}
|
||||
.layout-scrollbar {
|
||||
@extend .el-scrollbar;
|
||||
padding: 15px;
|
||||
}
|
||||
.el-scrollbar__view {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
/* 宽高 100%
|
||||
------------------------------- */
|
||||
.w100 {
|
||||
width: 100% !important;
|
||||
}
|
||||
.h100 {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
/* 字体大小全局样式
|
||||
------------------------------- */
|
||||
@for $i from 10 through 32 {
|
||||
.font#{$i} {
|
||||
font-size: #{$i}px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 外边距、内边距全局样式
|
||||
------------------------------- */
|
||||
@for $i from 5 through 20 {
|
||||
.mt#{$i} {
|
||||
margin-top: #{$i}px !important;
|
||||
|
@ -1,41 +1,37 @@
|
||||
/* 定义重用混入指令
|
||||
------------------------------- */
|
||||
@mixin transition($second: 0.3) {
|
||||
transition: all #{$second}s;
|
||||
}
|
||||
|
||||
@mixin translateX($opacity: 0, $offsetX: 0) {
|
||||
opacity: $opacity;
|
||||
transform: translateX(#{$offsetX}px);
|
||||
}
|
||||
|
||||
/* 页面切换动画
|
||||
------------------------------- */
|
||||
.fade-transform-enter-active,
|
||||
.fade-transform-leave-active {
|
||||
.slide-right-enter-active,
|
||||
.slide-right-leave-active,
|
||||
.slide-left-enter-active,
|
||||
.slide-left-leave-active {
|
||||
will-change: transform;
|
||||
@include transition();
|
||||
transition: all 0.3s ease;
|
||||
position: absolute;
|
||||
}
|
||||
.fade-transform-enter {
|
||||
@include translateX(-30);
|
||||
.slide-right-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
.fade-transform-leave-active {
|
||||
@include translateX(30);
|
||||
.slide-right-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
.slide-left-enter-from {
|
||||
@extend .slide-right-leave-to;
|
||||
}
|
||||
.slide-left-leave-to {
|
||||
@extend .slide-right-enter-from;
|
||||
}
|
||||
|
||||
/* Breadcrumb 面包屑过渡动画
|
||||
------------------------------- */
|
||||
.breadcrumb-enter-active,
|
||||
.breadcrumb-leave-active {
|
||||
@include transition();
|
||||
}
|
||||
.breadcrumb-enter,
|
||||
.breadcrumb-leave-active {
|
||||
@include translateX(20);
|
||||
}
|
||||
.breadcrumb-move {
|
||||
@include transition();
|
||||
}
|
||||
.breadcrumb-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
position: absolute;
|
||||
}
|
||||
.breadcrumb-enter-from,
|
||||
.breadcrumb-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
@ -666,23 +666,31 @@
|
||||
|
||||
/* NavMenu 导航菜单
|
||||
------------------------------- */
|
||||
// horizontal
|
||||
.el-menu--horizontal > .el-menu-item.is-active,
|
||||
.el-menu--horizontal > .el-submenu.is-active .el-submenu__title {
|
||||
.el-menu {
|
||||
border-right: none !important;
|
||||
}
|
||||
.el-menu-item.is-active,
|
||||
.el-submenu.is-active .el-submenu__title {
|
||||
border-bottom-color: set-color(primary);
|
||||
color: set-color(primary);
|
||||
}
|
||||
.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,
|
||||
.el-menu--horizontal .el-menu-item:not(.is-disabled):hover,
|
||||
.el-menu--horizontal > .el-submenu:focus .el-submenu__title,
|
||||
.el-menu--horizontal > .el-submenu:hover .el-submenu__title,
|
||||
.el-menu--horizontal .el-menu .el-menu-item.is-active,
|
||||
.el-menu--horizontal .el-menu .el-submenu.is-active > .el-submenu__title {
|
||||
.el-menu-item:not(.is-disabled):focus,
|
||||
.el-menu-item:not(.is-disabled):hover,
|
||||
.el-submenu:focus .el-submenu__title,
|
||||
.el-submenu:hover .el-submenu__title,
|
||||
.el-menu .el-menu-item.is-active,
|
||||
.el-menu .el-submenu.is-active > .el-submenu__title {
|
||||
color: set-color(primary);
|
||||
}
|
||||
.el-menu-item a,
|
||||
.el-menu-item a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
// default
|
||||
.el-menu-item.is-active {
|
||||
color: set-color(primary);
|
||||
background-color: set-color(primary-light-9);
|
||||
}
|
||||
.el-menu-item:focus,
|
||||
.el-menu-item:hover,
|
||||
@ -711,6 +719,11 @@
|
||||
.el-breadcrumb__inner.is-link:hover {
|
||||
color: set-color(primary);
|
||||
}
|
||||
.el-breadcrumb__inner a,
|
||||
.el-breadcrumb__inner.is-link {
|
||||
color: #303133;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* Dropdown 下拉菜单
|
||||
------------------------------- */
|
||||
@ -797,3 +810,13 @@
|
||||
background-color: set-color(primary-light-9);
|
||||
}
|
||||
}
|
||||
|
||||
/* scrollbar
|
||||
------------------------------- */
|
||||
.el-scrollbar__wrap {
|
||||
overflow-x: hidden !important;
|
||||
max-height: 100%; /*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
|
||||
}
|
||||
.el-select-dropdown .el-scrollbar__wrap {
|
||||
overflow-x: scroll !important;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import './app.scss';
|
||||
@import './base.scss';
|
||||
@import './element.scss';
|
||||
@import './media.scss';
|
||||
@import './media/media.scss';
|
||||
|
@ -1 +0,0 @@
|
||||
// 540/720/960/1140
|
35
vue-admin-wonderful-next/src/theme/media/error.scss
Normal file
35
vue-admin-wonderful-next/src/theme/media/error.scss
Normal file
@ -0,0 +1,35 @@
|
||||
@import './index.scss';
|
||||
|
||||
/* 页面宽度小于768px
|
||||
------------------------------- */
|
||||
@media screen and (max-width: $sm) {
|
||||
.error {
|
||||
.error-flex {
|
||||
flex-direction: column-reverse !important;
|
||||
height: auto !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
.right,
|
||||
.left {
|
||||
flex: unset !important;
|
||||
display: flex !important;
|
||||
}
|
||||
.left-item {
|
||||
margin: auto !important;
|
||||
}
|
||||
.right img {
|
||||
max-width: 450px !important;
|
||||
@extend .left-item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 页面宽度大于768px小于992px
|
||||
------------------------------- */
|
||||
@media screen and (min-width: $sm) and (max-width: $md) {
|
||||
.error {
|
||||
.error-flex {
|
||||
padding-left: 30px !important;
|
||||
}
|
||||
}
|
||||
}
|
12
vue-admin-wonderful-next/src/theme/media/index.scss
Normal file
12
vue-admin-wonderful-next/src/theme/media/index.scss
Normal file
@ -0,0 +1,12 @@
|
||||
/* 栅格布局(媒体查询变量)
|
||||
* $xs <768px 响应式栅格
|
||||
* $sm ≥768px 响应式栅格
|
||||
* $md ≥992px 响应式栅格
|
||||
* $lg ≥1200px 响应式栅格
|
||||
* $xl ≥1920px 响应式栅格
|
||||
------------------------------- */
|
||||
$xs: 576px;
|
||||
$sm: 768px;
|
||||
$md: 992px;
|
||||
$lg: 1200px;
|
||||
$xl: 1920px;
|
21
vue-admin-wonderful-next/src/theme/media/login.scss
Normal file
21
vue-admin-wonderful-next/src/theme/media/login.scss
Normal file
@ -0,0 +1,21 @@
|
||||
@import './index.scss';
|
||||
|
||||
/* 页面宽度小于576px
|
||||
------------------------------- */
|
||||
@media screen and (max-width: $xs) {
|
||||
.login-container {
|
||||
.login-content {
|
||||
width: 90% !important;
|
||||
padding: 20px 0 !important;
|
||||
}
|
||||
.login-content-form-btn {
|
||||
width: 100% !important;
|
||||
padding: 12px 0 !important;
|
||||
}
|
||||
.login-copyright {
|
||||
.login-copyright-msg {
|
||||
white-space: unset !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2
vue-admin-wonderful-next/src/theme/media/media.scss
Normal file
2
vue-admin-wonderful-next/src/theme/media/media.scss
Normal file
@ -0,0 +1,2 @@
|
||||
@import './login.scss';
|
||||
@import './error.scss';
|
26
vue-admin-wonderful-next/src/theme/media/template.scss
Normal file
26
vue-admin-wonderful-next/src/theme/media/template.scss
Normal file
@ -0,0 +1,26 @@
|
||||
@import './index.scss';
|
||||
|
||||
/* 页面宽度小于576px
|
||||
------------------------------- */
|
||||
@media screen and (max-width: $xs) {
|
||||
}
|
||||
|
||||
/* 页面宽度小于768px
|
||||
------------------------------- */
|
||||
@media screen and (max-width: $sm) {
|
||||
}
|
||||
|
||||
/* 页面宽度大于768px小于992px
|
||||
------------------------------- */
|
||||
@media screen and (min-width: $sm) and (max-width: $md) {
|
||||
}
|
||||
|
||||
/* 页面宽度大于992px小于1200px
|
||||
------------------------------- */
|
||||
@media screen and (min-width: $md) and (max-width: $lg) {
|
||||
}
|
||||
|
||||
/* 页面宽度大于1920px
|
||||
------------------------------- */
|
||||
@media screen and (min-width: $xl) {
|
||||
}
|
@ -78,26 +78,26 @@ export function formatPast(param: any, format: string = "YYYY-mm-dd") {
|
||||
time = Number.parseInt(`${time - t}`)
|
||||
if (time < 10000) {
|
||||
// 10秒内
|
||||
return "刚刚";
|
||||
return "刚刚"
|
||||
} else if (time < 60000 && time >= 10000) {
|
||||
// 超过10秒少于1分钟内
|
||||
s = Math.floor(time / 1000);
|
||||
return `${s}秒前`;
|
||||
s = Math.floor(time / 1000)
|
||||
return `${s}秒前`
|
||||
} else if (time < 3600000 && time >= 60000) {
|
||||
// 超过1分钟少于1小时
|
||||
s = Math.floor(time / 60000);
|
||||
return `${s}分钟前`;
|
||||
s = Math.floor(time / 60000)
|
||||
return `${s}分钟前`
|
||||
} else if (time < 86400000 && time >= 3600000) {
|
||||
// 超过1小时少于24小时
|
||||
s = Math.floor(time / 3600000);
|
||||
return `${s}小时前`;
|
||||
s = Math.floor(time / 3600000)
|
||||
return `${s}小时前`
|
||||
} else if (time < 259200000 && time >= 86400000) {
|
||||
// 超过1天少于3天内
|
||||
s = Math.floor(time / 86400000);
|
||||
return `${s}天前`;
|
||||
s = Math.floor(time / 86400000)
|
||||
return `${s}天前`
|
||||
} else {
|
||||
// 超过3天
|
||||
let date = typeof param === "string" || "object" ? new Date(param) : param;
|
||||
let date = typeof param === "string" || "object" ? new Date(param) : param
|
||||
return formatDate(date, format);
|
||||
}
|
||||
}
|
||||
|
10
vue-admin-wonderful-next/src/utils/setIconfont.ts
Normal file
10
vue-admin-wonderful-next/src/utils/setIconfont.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// 动态设置字体图标
|
||||
export function setIconfont(url: Array<string> = []) {
|
||||
if (url.length <= 0) return false
|
||||
url.map(v => {
|
||||
let link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = v
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
})
|
||||
}
|
37
vue-admin-wonderful-next/src/utils/storage.ts
Normal file
37
vue-admin-wonderful-next/src/utils/storage.ts
Normal file
@ -0,0 +1,37 @@
|
||||
// 1. localStorage
|
||||
// 设置永久缓存
|
||||
export function setLocal(key: string, val: any) {
|
||||
window.localStorage.setItem(key, JSON.stringify(val))
|
||||
}
|
||||
// 获取永久缓存
|
||||
export function getLocal(key: string) {
|
||||
let json: any = window.localStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
}
|
||||
// 移除永久缓存
|
||||
export function removeLocal(key: string) {
|
||||
window.localStorage.removeItem(key)
|
||||
}
|
||||
// 移除全部永久缓存
|
||||
export function clearLocal() {
|
||||
window.localStorage.clear()
|
||||
}
|
||||
|
||||
// 2. sessionStorage
|
||||
// 设置临时缓存
|
||||
export function setSession(key: string, val: any) {
|
||||
window.sessionStorage.setItem(key, JSON.stringify(val))
|
||||
}
|
||||
// 获取临时缓存
|
||||
export function getSession(key: string) {
|
||||
let json: any = window.sessionStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
}
|
||||
// 移除临时缓存
|
||||
export function removeSession(key: string) {
|
||||
window.sessionStorage.removeItem(key)
|
||||
}
|
||||
// 移除全部临时缓存
|
||||
export function clearSession() {
|
||||
window.sessionStorage.clear()
|
||||
}
|
@ -1,39 +1,39 @@
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// hex颜色转rgb颜色
|
||||
export function hexToRgb(str: any) {
|
||||
let hexs: any = '';
|
||||
let reg = /^\#?[0-9A-F]{6}$/;
|
||||
if (!reg.test(str)) return ElMessage({ type: 'warning', message: "输入错误的hex" });
|
||||
str = str.replace("#", "");
|
||||
hexs = str.match(/../g);
|
||||
for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16);
|
||||
return hexs;
|
||||
let hexs: any = ''
|
||||
let reg = /^\#?[0-9A-F]{6}$/
|
||||
if (!reg.test(str)) return ElMessage({ type: 'warning', message: "输入错误的hex" })
|
||||
str = str.replace("#", "")
|
||||
hexs = str.match(/../g)
|
||||
for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16)
|
||||
return hexs
|
||||
}
|
||||
|
||||
// rgb颜色转Hex颜色
|
||||
export function rgbToHex(r: any, g: any, b: any) {
|
||||
let reg = /^\d{1,3}$/;
|
||||
if (!reg.test(r) || !reg.test(g) || !reg.test(b)) return ElMessage({ type: 'warning', message: "输入错误的rgb颜色值" });
|
||||
let hexs = [r.toString(16), g.toString(16), b.toString(16)];
|
||||
for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`;
|
||||
return `#${hexs.join("")}`;
|
||||
let reg = /^\d{1,3}$/
|
||||
if (!reg.test(r) || !reg.test(g) || !reg.test(b)) return ElMessage({ type: 'warning', message: "输入错误的rgb颜色值" })
|
||||
let hexs = [r.toString(16), g.toString(16), b.toString(16)]
|
||||
for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`
|
||||
return `#${hexs.join("")}`
|
||||
}
|
||||
|
||||
// 加深颜色值,level为加深的程度,限0-1之间
|
||||
export function getDarkColor(color: any, level: number) {
|
||||
let reg = /^\#?[0-9A-F]{6}$/;
|
||||
if (!reg.test(color)) return ElMessage({ type: 'warning', message: "输入错误的hex颜色值" });
|
||||
let rgb = hexToRgb(color);
|
||||
for (let i = 0; i < 3; i++) rgb[i] = Math.floor(rgb[i] * (1 - level));
|
||||
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
||||
let reg = /^\#?[0-9A-F]{6}$/
|
||||
if (!reg.test(color)) return ElMessage({ type: 'warning', message: "输入错误的hex颜色值" })
|
||||
let rgb = hexToRgb(color)
|
||||
for (let i = 0; i < 3; i++) rgb[i] = Math.floor(rgb[i] * (1 - level))
|
||||
return rgbToHex(rgb[0], rgb[1], rgb[2])
|
||||
}
|
||||
|
||||
// 变浅颜色值,level为加深的程度,限0-1之间
|
||||
export function getLightColor(color: any, level: number) {
|
||||
let reg = /^\#?[0-9A-F]{6}$/;
|
||||
if (!reg.test(color)) return ElMessage({ type: 'warning', message: "输入错误的hex颜色值" });
|
||||
let rgb = hexToRgb(color);
|
||||
for (let i = 0; i < 3; i++) rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]);
|
||||
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
||||
let reg = /^\#?[0-9A-F]{6}$/
|
||||
if (!reg.test(color)) return ElMessage({ type: 'warning', message: "输入错误的hex颜色值" })
|
||||
let rgb = hexToRgb(color)
|
||||
for (let i = 0; i < 3; i++) rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i])
|
||||
return rgbToHex(rgb[0], rgb[1], rgb[2])
|
||||
}
|
0
vue-admin-wonderful-next/src/utils/themeConfig.ts
Normal file
0
vue-admin-wonderful-next/src/utils/themeConfig.ts
Normal file
@ -1,43 +1,43 @@
|
||||
// 页面添加水印效果
|
||||
const setWatermark = (str: any) => {
|
||||
const id = "1.23452384164.123412416";
|
||||
if (document.getElementById(id) !== null) document.body.removeChild(document.getElementById(id) as any);
|
||||
const can = document.createElement("canvas");
|
||||
can.width = 250;
|
||||
can.height = 180;
|
||||
const cans: any = can.getContext("2d");
|
||||
cans.rotate((-20 * Math.PI) / 180);
|
||||
cans.font = "12px Vedana";
|
||||
cans.fillStyle = "rgba(200, 200, 200, 0.30)";
|
||||
cans.textAlign = "center";
|
||||
cans.textBaseline = "Middle";
|
||||
cans.fillText(str, can.width / 10, can.height / 2);
|
||||
const div = document.createElement("div");
|
||||
div.id = id;
|
||||
div.style.pointerEvents = "none";
|
||||
div.style.top = "35px";
|
||||
div.style.left = "0px";
|
||||
div.style.position = "fixed";
|
||||
div.style.zIndex = "100000";
|
||||
div.style.width = document.documentElement.clientWidth + "px";
|
||||
div.style.height = document.documentElement.clientHeight + "px";
|
||||
div.style.background = `url(${can.toDataURL("image/png")}) left top repeat`;
|
||||
document.body.appendChild(div);
|
||||
return id;
|
||||
const id = "1.23452384164.123412416"
|
||||
if (document.getElementById(id) !== null) document.body.removeChild(document.getElementById(id) as any)
|
||||
const can = document.createElement("canvas")
|
||||
can.width = 250
|
||||
can.height = 180
|
||||
const cans: any = can.getContext("2d")
|
||||
cans.rotate((-20 * Math.PI) / 180)
|
||||
cans.font = "12px Vedana"
|
||||
cans.fillStyle = "rgba(200, 200, 200, 0.30)"
|
||||
cans.textAlign = "center"
|
||||
cans.textBaseline = "Middle"
|
||||
cans.fillText(str, can.width / 10, can.height / 2)
|
||||
const div = document.createElement("div")
|
||||
div.id = id
|
||||
div.style.pointerEvents = "none"
|
||||
div.style.top = "35px"
|
||||
div.style.left = "0px"
|
||||
div.style.position = "fixed"
|
||||
div.style.zIndex = "100000"
|
||||
div.style.width = document.documentElement.clientWidth + "px"
|
||||
div.style.height = document.documentElement.clientHeight + "px"
|
||||
div.style.background = `url(${can.toDataURL("image/png")}) left top repeat`
|
||||
document.body.appendChild(div)
|
||||
return id
|
||||
};
|
||||
|
||||
const watermark = {
|
||||
// 设置水印
|
||||
set: (str: any) => {
|
||||
let id = setWatermark(str);
|
||||
if (document.getElementById(id) === null) id = setWatermark(str);
|
||||
window.onresize = () => { setWatermark(str) };
|
||||
let id = setWatermark(str)
|
||||
if (document.getElementById(id) === null) id = setWatermark(str)
|
||||
window.onresize = () => { setWatermark(str) }
|
||||
},
|
||||
// 删除水印
|
||||
del: () => {
|
||||
let id = '1.23452384164.123412416';
|
||||
if (document.getElementById(id) !== null) document.body.removeChild(document.getElementById(id) as any);
|
||||
let id = '1.23452384164.123412416'
|
||||
if (document.getElementById(id) !== null) document.body.removeChild(document.getElementById(id) as any)
|
||||
}
|
||||
}
|
||||
|
||||
export default watermark;
|
||||
export default watermark
|
3
vue-admin-wonderful-next/src/views/docs copy 1/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 1/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 2/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 2/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 3/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 3/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 4/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 4/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 5/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 5/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 6/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 6/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 7/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 7/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 8/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 8/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs copy 9/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs copy 9/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
3
vue-admin-wonderful-next/src/views/docs/index.vue
Normal file
3
vue-admin-wonderful-next/src/views/docs/index.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
docs
|
||||
</template>
|
113
vue-admin-wonderful-next/src/views/error/401.vue
Normal file
113
vue-admin-wonderful-next/src/views/error/401.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div class="error">
|
||||
<div class="error-flex">
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">401</div>
|
||||
<div class="left-item-animation left-item-title">您未被授权,没有操作权限~</div>
|
||||
<div class="left-item-animation left-item-msg">联系方式:加QQ群探讨 665452019</div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" round @click="onSetAuth">重新授权</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<img src="https://gitee.com/lyt-top/vue-admin-wonderful-images/raw/master/images/error/401.png" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
import { clearSession } from "/@/utils/storage.ts";
|
||||
export default {
|
||||
name: "401",
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const onSetAuth = () => {
|
||||
clearSession();
|
||||
router.push("/login");
|
||||
};
|
||||
return {
|
||||
onSetAuth,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.error {
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
.error-flex {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
height: 350px;
|
||||
width: 900px;
|
||||
.left {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
.left-item {
|
||||
.left-item-animation {
|
||||
opacity: 0;
|
||||
animation-name: error-num;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
.left-item-num {
|
||||
color: #d6e0f6;
|
||||
font-size: 55px;
|
||||
}
|
||||
.left-item-title {
|
||||
font-size: 20px;
|
||||
color: #333333;
|
||||
margin: 15px 0 5px 0;
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
.left-item-msg {
|
||||
color: #c0bebe;
|
||||
font-size: 12px;
|
||||
margin-bottom: 30px;
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
.left-item-btn {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
flex: 1;
|
||||
opacity: 0;
|
||||
animation-name: error-img;
|
||||
animation-duration: 2s;
|
||||
animation-fill-mode: forwards;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@keyframes error-num {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes error-img {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
111
vue-admin-wonderful-next/src/views/error/404.vue
Normal file
111
vue-admin-wonderful-next/src/views/error/404.vue
Normal file
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="error">
|
||||
<div class="error-flex">
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">404</div>
|
||||
<div class="left-item-animation left-item-title">地址输入错误,请重新输入地址~</div>
|
||||
<div class="left-item-animation left-item-msg">您可以先检查网址,然后重新输入或给我们反馈问题。</div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" round @click="onGoHome">返回首页</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<img src="https://gitee.com/lyt-top/vue-admin-wonderful-images/raw/master/images/error/404.png" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
export default {
|
||||
name: "404",
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const onGoHome = () => {
|
||||
router.push("/");
|
||||
};
|
||||
return {
|
||||
onGoHome,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.error {
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
.error-flex {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
height: 350px;
|
||||
width: 900px;
|
||||
.left {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
.left-item {
|
||||
.left-item-animation {
|
||||
opacity: 0;
|
||||
animation-name: error-num;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
.left-item-num {
|
||||
color: #d6e0f6;
|
||||
font-size: 55px;
|
||||
}
|
||||
.left-item-title {
|
||||
font-size: 20px;
|
||||
color: #333333;
|
||||
margin: 15px 0 5px 0;
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
.left-item-msg {
|
||||
color: #c0bebe;
|
||||
font-size: 12px;
|
||||
margin-bottom: 30px;
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
.left-item-btn {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
flex: 1;
|
||||
opacity: 0;
|
||||
animation-name: error-img;
|
||||
animation-duration: 2s;
|
||||
animation-fill-mode: forwards;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@keyframes error-num {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes error-img {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,5 +1,85 @@
|
||||
<template>
|
||||
home
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home</p>
|
||||
<p>home123123</p>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
154
vue-admin-wonderful-next/src/views/layout/component/aside.vue
Normal file
154
vue-admin-wonderful-next/src/views/layout/component/aside.vue
Normal file
@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<el-aside width="240px">
|
||||
<el-scrollbar>
|
||||
<Vertical :menuList="menuList" />
|
||||
</el-scrollbar>
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vertical from "/@/views/layout/navMenu/vertical.vue";
|
||||
import { toRefs, reactive } from "vue";
|
||||
export default {
|
||||
name: "layoutAside",
|
||||
components: { Vertical },
|
||||
setup() {
|
||||
const state = reactive({
|
||||
menuList: [
|
||||
{
|
||||
path: "/home",
|
||||
meta: {
|
||||
title: "首页",
|
||||
icon: "el-icon-s-home",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/docs3",
|
||||
meta: {
|
||||
title: "文档3",
|
||||
icon: "el-icon-s-flag",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs1",
|
||||
meta: {
|
||||
title: "文档1",
|
||||
icon: "el-icon-s-flag",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs2",
|
||||
meta: {
|
||||
title: "文档2",
|
||||
icon: "el-icon-s-flag",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/docs",
|
||||
meta: {
|
||||
title: "文档",
|
||||
icon: "el-icon-s-management",
|
||||
isLink: "https://www.ele.me",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs4",
|
||||
meta: {
|
||||
title: "文档4",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs5",
|
||||
meta: {
|
||||
title: "文档5",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs6",
|
||||
meta: {
|
||||
title: "文档6",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs7",
|
||||
meta: {
|
||||
title: "文档7",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs8",
|
||||
meta: {
|
||||
title: "文档8",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs9",
|
||||
meta: {
|
||||
title: "文档9",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs10",
|
||||
meta: {
|
||||
title: "文档10",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs11",
|
||||
meta: {
|
||||
title: "文档11",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs12",
|
||||
meta: {
|
||||
title: "文档12",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs13",
|
||||
meta: {
|
||||
title: "文档13",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs14",
|
||||
meta: {
|
||||
title: "文档14",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs15",
|
||||
meta: {
|
||||
title: "文档15",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/docs16",
|
||||
meta: {
|
||||
title: "文档16",
|
||||
icon: "el-icon-s-management",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return {
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<el-header height="84px">
|
||||
<NavBarsIndex />
|
||||
</el-header>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import NavBarsIndex from "/@/views/layout/navBars/index.vue";
|
||||
export default {
|
||||
name: "layoutHeader",
|
||||
components: { NavBarsIndex },
|
||||
};
|
||||
</script>
|
35
vue-admin-wonderful-next/src/views/layout/component/main.vue
Normal file
35
vue-admin-wonderful-next/src/views/layout/component/main.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<el-main>
|
||||
<el-scrollbar class="layout-scrollbar">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition appear :name="transitionName" mode="out-in">
|
||||
<div :key="key">
|
||||
<keep-alive>
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</div>
|
||||
</transition>
|
||||
</router-view>
|
||||
</el-scrollbar>
|
||||
</el-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, toRefs, reactive } from "vue";
|
||||
import { useRoute, onBeforeRouteUpdate } from "vue-router";
|
||||
export default defineComponent({
|
||||
name: "layoutMain",
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const state = reactive({
|
||||
transitionName: "slide-right",
|
||||
});
|
||||
const key = computed(() => route.path);
|
||||
onBeforeRouteUpdate((to, from) => {
|
||||
state.transitionName =
|
||||
to.meta.index > from.meta.index ? "slide-right" : "slide-left";
|
||||
});
|
||||
return { key, ...toRefs(state) };
|
||||
},
|
||||
});
|
||||
</script>
|
21
vue-admin-wonderful-next/src/views/layout/fashion.vue
Normal file
21
vue-admin-wonderful-next/src/views/layout/fashion.vue
Normal file
@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<el-container class="layout-container">
|
||||
<Aside />
|
||||
<el-container>
|
||||
<el-scrollbar>
|
||||
<Header />
|
||||
<Main />
|
||||
</el-scrollbar>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Aside from '/@/views/layout/component/aside.vue';
|
||||
import Header from '/@/views/layout/component/header.vue';
|
||||
import Main from '/@/views/layout/component/main.vue';
|
||||
export default {
|
||||
name: 'layoutFashion',
|
||||
components: { Aside, Header, Main }
|
||||
}
|
||||
</script>
|
@ -1,10 +1,11 @@
|
||||
<template>
|
||||
layout
|
||||
<router-view></router-view>
|
||||
<Fashion />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Fashion from "/@/views/layout/fashion.vue";
|
||||
export default {
|
||||
name: "layout",
|
||||
components: { Fashion },
|
||||
};
|
||||
</script>
|
9
vue-admin-wonderful-next/src/views/layout/logo/index.vue
Normal file
9
vue-admin-wonderful-next/src/views/layout/logo/index.vue
Normal file
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
layoutLogo
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "layoutLogo",
|
||||
};
|
||||
</script>
|
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="layout-navbars-breadcrumb">
|
||||
<i class="el-icon-s-fold layout-navbars-breadcrumb-icon"></i>
|
||||
<el-breadcrumb>
|
||||
<transition-group name="breadcrumb" mode="out-in">
|
||||
<el-breadcrumb-item v-for="(v,k) in breadcrumbList" :key="v.meta.title">
|
||||
<span v-if="k === breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span">{{v.meta.title}}</span>
|
||||
<a v-else @click.prevent="onBreadcrumbClick(v)">{{v.meta.title}}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { toRefs, reactive, onBeforeMount } from "vue";
|
||||
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
|
||||
export default {
|
||||
name: "layoutBreadcrumb",
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = reactive({
|
||||
breadcrumbList: [{ meta: { title: "" } }], // 定义初始值,不能为空数组,否则 v-for 报错
|
||||
});
|
||||
const getBreadcrumbList = (matched: any) => {
|
||||
state.breadcrumbList = matched;
|
||||
};
|
||||
const onBreadcrumbClick = (v: object) => {
|
||||
const { redirect, path } = v;
|
||||
if (redirect) router.push(redirect);
|
||||
else router.push(path);
|
||||
};
|
||||
onBeforeMount(() => {
|
||||
state.breadcrumbList = route.matched;
|
||||
});
|
||||
onBeforeRouteUpdate((to) => {
|
||||
getBreadcrumbList(to.matched);
|
||||
});
|
||||
return {
|
||||
onBreadcrumbClick,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-navbars-breadcrumb {
|
||||
flex: 1;
|
||||
height: inherit;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.layout-navbars-breadcrumb-icon {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.layout-navbars-breadcrumb-span {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div class="layout-navbars-breadcrumb-index">
|
||||
<Breadcrumb />
|
||||
<User />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Breadcrumb from "/@/views/layout/navBars/breadcrumb/breadcrumb.vue";
|
||||
import User from "/@/views/layout/navBars/breadcrumb/user.vue";
|
||||
export default {
|
||||
name: "layoutBreadcrumbIndex",
|
||||
components: { Breadcrumb, User },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-navbars-breadcrumb-index {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid rgb(230, 230, 230);
|
||||
padding: 0 15px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
layoutBreadcrumbSeting
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "layoutBreadcrumbSeting",
|
||||
};
|
||||
</script>
|
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="layout-navbars-breadcrumb-user">
|
||||
<i class="el-icon-search layout-navbars-breadcrumb-user-icon" title="菜单搜索"></i>
|
||||
<i class="el-icon-setting layout-navbars-breadcrumb-user-icon" title="布局配置"></i>
|
||||
<i class="el-icon-bell layout-navbars-breadcrumb-user-icon" title="消息"></i>
|
||||
<i class="icon-fullscreen iconfont layout-navbars-breadcrumb-user-icon mr10" title="开全屏"></i>
|
||||
<el-dropdown :show-timeout="70" :hide-timeout="50">
|
||||
<span class="layout-navbars-breadcrumb-user-link">
|
||||
<img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg"
|
||||
class="layout-navbars-breadcrumb-user-link-photo mr5" /> small@小柒
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>个人中心</el-dropdown-item>
|
||||
<el-dropdown-item>首页</el-dropdown-item>
|
||||
<el-dropdown-item>文档</el-dropdown-item>
|
||||
<el-dropdown-item>404</el-dropdown-item>
|
||||
<el-dropdown-item>401</el-dropdown-item>
|
||||
<el-dropdown-item divided>退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "layoutBreadcrumbUser",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-navbars-breadcrumb-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&-link {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&-photo {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
&-icon {
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
color: #000000;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
24
vue-admin-wonderful-next/src/views/layout/navBars/index.vue
Normal file
24
vue-admin-wonderful-next/src/views/layout/navBars/index.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div class="layout-navbars-container">
|
||||
<BreadcrumbIndex />
|
||||
<TagsView />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import BreadcrumbIndex from "/@/views/layout/navBars/breadcrumb/index.vue";
|
||||
import TagsView from "/@/views/layout/navBars/tagsView/tagsView.vue";
|
||||
export default {
|
||||
name: "layoutNavBars",
|
||||
components: { BreadcrumbIndex, TagsView },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-navbars-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<transition name="el-zoom-in-center">
|
||||
<div aria-hidden="true" class="el-dropdown__popper el-popper is-light is-pure custom-contextmenu" role="tooltip"
|
||||
data-popper-placement="bottom" :style="`top: ${dropdown.y + 5}px;left: ${dropdown.x}px;`" v-show="isShow">
|
||||
<ul class="el-dropdown-menu">
|
||||
<li class="el-dropdown-menu__item" aria-disabled="false" tabindex="-1" v-for="(v,k) in dropdownList" :key="k">
|
||||
<i :class="v.icon"></i>
|
||||
<span>{{v.txt}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="el-popper__arrow" style="left:10px"></div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
reactive,
|
||||
toRefs,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
} from "vue";
|
||||
export default defineComponent({
|
||||
name: "layoutTagsViewContextmenu",
|
||||
props: {
|
||||
dropdown: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const state = reactive({
|
||||
isShow: false,
|
||||
dropdownList: [
|
||||
{ id: 0, txt: "刷新", affix: false, icon: "el-icon-refresh-right" },
|
||||
{ id: 1, txt: "关闭", affix: true, icon: "el-icon-close" },
|
||||
{ id: 2, txt: "关闭其它", affix: false, icon: "el-icon-circle-close" },
|
||||
{ id: 3, txt: "全部关闭", affix: false, icon: "el-icon-folder-delete" },
|
||||
],
|
||||
});
|
||||
const dropdown = computed(() => {
|
||||
return props.dropdown;
|
||||
});
|
||||
const openContextmenu = () => {
|
||||
closeContextmenu();
|
||||
setTimeout(() => {
|
||||
state.isShow = true;
|
||||
}, 10);
|
||||
};
|
||||
const closeContextmenu = () => {
|
||||
state.isShow = false;
|
||||
};
|
||||
onMounted(() => {
|
||||
document.body.addEventListener("click", closeContextmenu);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
document.body.removeEventListener("click", closeContextmenu);
|
||||
});
|
||||
return {
|
||||
dropdown,
|
||||
openContextmenu,
|
||||
closeContextmenu,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-contextmenu {
|
||||
transform-origin: center top;
|
||||
z-index: 2190;
|
||||
position: fixed;
|
||||
.el-dropdown-menu__item {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<el-scrollbar ref="elScrollbarRef" @wheel.native.prevent="onHandleScroll">
|
||||
<slot />
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { getCurrentInstance, reactive, nextTick, toRefs } from "vue";
|
||||
export default {
|
||||
setup() {
|
||||
const { proxy } = getCurrentInstance();
|
||||
const state = reactive({
|
||||
tagsArr: [],
|
||||
});
|
||||
const onHandleScroll = (e: object) => {
|
||||
const eventDelta = e.wheelDelta || -e.deltaY * 40;
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft =
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft + eventDelta / 4;
|
||||
};
|
||||
const setScrollLeft = (tags: Array<object> = []) => {
|
||||
nextTick(() => {
|
||||
state.tagsArr = tags.value;
|
||||
});
|
||||
};
|
||||
const moveToTarget = (currentTag: any) => {
|
||||
const tagList = state.tagsArr;
|
||||
let firstTag = null;
|
||||
let lastTag = null;
|
||||
if (tagList.length > 0) {
|
||||
firstTag = tagList[0];
|
||||
lastTag = tagList[tagList.length - 1];
|
||||
}
|
||||
if (firstTag === currentTag) {
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft = 0;
|
||||
} else if (lastTag === currentTag) {
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft =
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollWidth -
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.offsetWidth;
|
||||
} else {
|
||||
const currentIndex = tagList.findIndex((item) => item === currentTag);
|
||||
const prevTag = tagList[currentIndex - 1];
|
||||
const nextTag = tagList[currentIndex + 1];
|
||||
const afterNextTagOffsetLeft =
|
||||
nextTag.offsetLeft + nextTag.offsetWidth + 4;
|
||||
const beforePrevTagOffsetLeft = prevTag.offsetLeft - 4;
|
||||
if (
|
||||
afterNextTagOffsetLeft >
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft +
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.offsetWidth
|
||||
) {
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft =
|
||||
afterNextTagOffsetLeft -
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.offsetWidth;
|
||||
} else if (
|
||||
beforePrevTagOffsetLeft <
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft
|
||||
) {
|
||||
proxy.$refs.elScrollbarRef.$refs.wrap.scrollLeft = beforePrevTagOffsetLeft;
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
setScrollLeft,
|
||||
onHandleScroll,
|
||||
moveToTarget,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div class="layout-navbars-tagsview">
|
||||
<Scroll ref="scrollRef">
|
||||
<ul class="layout-navbars-tagsview-ul">
|
||||
<li v-for="(v,k) in arr2" :key="k" class="layout-navbars-tagsview-ul-li" :class="{'is-active':isActive(v.path)}"
|
||||
@contextmenu.prevent="onContextmenu(v,$event)" @click="onTagsClick(v,k)"
|
||||
:ref="el => { if (el) tagsRefs[k] = el }">
|
||||
<i class="iconfont icon-webicon318 layout-navbars-tagsview-ul-li-iconfont" v-if="isActive(v.path)"></i>
|
||||
<span>{{v.name}}</span>
|
||||
<template v-if="isActive(v.path)">
|
||||
<i class="el-icon-refresh-right ml5"></i>
|
||||
<i class="el-icon-close layout-navbars-tagsview-ul-li-icon"></i>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
</Scroll>
|
||||
</div>
|
||||
<Contextmenu :dropdown="dropdown" ref="contextmenuRef" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
toRefs,
|
||||
reactive,
|
||||
onMounted,
|
||||
computed,
|
||||
ref,
|
||||
nextTick,
|
||||
onBeforeUpdate,
|
||||
} from "vue";
|
||||
import { useRoute, useRouter, onBeforeRouteUpdate } from "vue-router";
|
||||
import Sortable from "sortablejs";
|
||||
import Contextmenu from "/@/views/layout/navBars/tagsView/contextmenu.vue";
|
||||
import Scroll from "/@/views/layout/navBars/tagsView/scroll.vue";
|
||||
export default {
|
||||
name: "layoutTagsView",
|
||||
components: { Contextmenu, Scroll },
|
||||
setup() {
|
||||
const tagsRefs = ref([]);
|
||||
const scrollRef = ref();
|
||||
const contextmenuRef = ref();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = reactive({
|
||||
routePath: route.path,
|
||||
dropdown: {
|
||||
x: "",
|
||||
y: "",
|
||||
},
|
||||
tagsRefsIndex: 0,
|
||||
arr2: [
|
||||
{ id: 11, name: "微软", path: "/home" },
|
||||
{ id: 12, name: "亚马逊", path: "/docs" },
|
||||
{ id: 13, name: "京东1", path: "/docs1" },
|
||||
{ id: 15, name: "谷歌2", path: "/docs2" },
|
||||
{ id: 1, name: "苹果3", path: "/docs3" },
|
||||
{ id: 14, name: "苹果4", path: "/docs4" },
|
||||
{ id: 14, name: "苹果5", path: "/docs5" },
|
||||
{ id: 14, name: "苹果6", path: "/docs6" },
|
||||
{ id: 14, name: "苹果7", path: "/docs7" },
|
||||
{ id: 14, name: "苹果8", path: "/docs8" },
|
||||
{ id: 14, name: "苹果9", path: "/docs9" },
|
||||
{ id: 14, name: "苹果10", path: "/docs10" },
|
||||
{ id: 14, name: "苹果11", path: "/docs11" },
|
||||
{ id: 14, name: "苹果12", path: "/docs12" },
|
||||
{ id: 14, name: "苹果13", path: "/docs13" },
|
||||
{ id: 14, name: "苹果14", path: "/docs14" },
|
||||
{ id: 14, name: "苹果15", path: "/docs15" },
|
||||
{ id: 14, name: "苹果16", path: "/docs16" },
|
||||
],
|
||||
});
|
||||
const initSortable = () => {
|
||||
const el = document.querySelector(".layout-navbars-tagsview-ul");
|
||||
const sortable = Sortable.create(el, { animation: 300 });
|
||||
};
|
||||
const isActive = (path: string) => {
|
||||
return path === state.routePath;
|
||||
};
|
||||
const onContextmenu = (v: object, e: object) => {
|
||||
const { clientX, clientY } = e;
|
||||
state.dropdown.x = clientX;
|
||||
state.dropdown.y = clientY;
|
||||
contextmenuRef.value.openContextmenu();
|
||||
};
|
||||
const onTagsClick = (v: object, k: number) => {
|
||||
state.tagsRefsIndex = k;
|
||||
router.push(v.path);
|
||||
};
|
||||
const moveToCurrentTag = () => {
|
||||
nextTick(() => {
|
||||
scrollRef.value.moveToTarget(tagsRefs.value[state.tagsRefsIndex]);
|
||||
});
|
||||
};
|
||||
const getTagsRefsIndex = (path: string) => {
|
||||
if (state.arr2.length > 0) {
|
||||
state.tagsRefsIndex = state.arr2.findIndex(
|
||||
(item) => item.path === path
|
||||
);
|
||||
}
|
||||
};
|
||||
onBeforeUpdate(() => {
|
||||
tagsRefs.value = [];
|
||||
});
|
||||
onMounted(() => {
|
||||
initSortable();
|
||||
scrollRef.value.setScrollLeft(tagsRefs);
|
||||
});
|
||||
onBeforeRouteUpdate((to) => {
|
||||
state.routePath = to.path;
|
||||
getTagsRefsIndex(to.path);
|
||||
moveToCurrentTag();
|
||||
});
|
||||
return {
|
||||
isActive,
|
||||
onContextmenu,
|
||||
onTagsClick,
|
||||
tagsRefs,
|
||||
contextmenuRef,
|
||||
scrollRef,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-navbars-tagsview {
|
||||
flex: 1;
|
||||
&-ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #606266;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
padding: 0 15px;
|
||||
&-li {
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid #e6e6e6;
|
||||
padding: 0 15px;
|
||||
margin-right: 5px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
justify-content: space-between;
|
||||
&:hover {
|
||||
background: #f6f6f6;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
&-iconfont {
|
||||
position: relative;
|
||||
left: -5px;
|
||||
}
|
||||
&-icon {
|
||||
border-radius: 100%;
|
||||
position: relative;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
text-align: center;
|
||||
line-height: 14px;
|
||||
right: -5px;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: var(--color-primary-light-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
.is-active {
|
||||
color: #ffffff;
|
||||
background: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<template v-for="val in chil">
|
||||
<el-submenu :index="val.path" :key="val.path" v-if="val.children && val.children.length > 0">
|
||||
<template #title>
|
||||
<i :class="val.meta.icon"></i>
|
||||
{{ val.meta.title }}
|
||||
</template>
|
||||
<sub-item :chil="val.children" />
|
||||
</el-submenu>
|
||||
<el-menu-item :index="val.path" :key="val.path" v-else>
|
||||
<i :class="val.meta.icon ? val.meta.icon : ''"></i>
|
||||
<template v-if="!val.meta.isLink">{{ val.meta.title }}</template>
|
||||
<template v-else><a :href="val.meta.isLink" target="_blank">{{ val.meta.title }}</a></template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
export default defineComponent({
|
||||
name: "navMenuSubItem",
|
||||
props: {
|
||||
chil: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const route = useRoute();
|
||||
const chil = computed(() => {
|
||||
return props.chil;
|
||||
});
|
||||
return {
|
||||
chil,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<el-menu router :default-active="defaultActive" background-color="#29384D" text-color="#e6e6e6">
|
||||
<template v-for="val in menuList">
|
||||
<el-submenu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
|
||||
<template #title>
|
||||
<i :class="val.meta.icon ? val.meta.icon : ''"></i>
|
||||
<span>{{ val.meta.title }}</span>
|
||||
</template>
|
||||
<SubItem :chil="val.children" />
|
||||
</el-submenu>
|
||||
<el-menu-item :index="val.path" :key="val.path" v-else>
|
||||
<i :class="val.meta.icon ? val.meta.icon : ''"></i>
|
||||
<template #title v-if="!val.meta.isLink">{{ val.meta.title }}</template>
|
||||
<template #title v-else><a :href="val.meta.isLink" target="_blank">{{ val.meta.title }}</a></template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { toRefs, reactive, computed, defineComponent } from "vue";
|
||||
import { useRoute, onBeforeRouteUpdate } from "vue-router";
|
||||
import SubItem from "/@/views/layout/navMenu/subItem.vue";
|
||||
export default defineComponent({
|
||||
name: "navMenuVertical",
|
||||
components: { SubItem },
|
||||
props: {
|
||||
menuList: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const route = useRoute();
|
||||
const state = reactive({
|
||||
defaultActive: route.path,
|
||||
});
|
||||
const menuList = computed(() => {
|
||||
return props.menuList;
|
||||
});
|
||||
onBeforeRouteUpdate((to) => {
|
||||
state.defaultActive = to.path;
|
||||
});
|
||||
return {
|
||||
menuList,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
@ -12,7 +12,7 @@
|
||||
v-model="ruleForm.code" clearable autocomplete="off"></el-input>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-button>获取验证码</el-button>
|
||||
<el-button class="login-content-form-btn">获取验证码</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
@ -23,8 +23,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-copyright">
|
||||
<div class="mb5">版权所有:深圳市xxx软件科技有限公司</div>
|
||||
<div>Copyright: Shenzhen XXX Software Technology Co. Ltd 粤ICP备05010000号</div>
|
||||
<div class="mb5 login-copyright-company">版权所有:深圳市xxx软件科技有限公司</div>
|
||||
<div class="login-copyright-msg">Copyright: Shenzhen XXX Software Technology 粤ICP备05010000号</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -32,12 +32,11 @@
|
||||
<script lang="ts">
|
||||
import Account from "/@/views/login/component/account.vue";
|
||||
import Mobile from "/@/views/login/component/mobile.vue";
|
||||
import { toRefs, reactive, getCurrentInstance } from "vue";
|
||||
import { toRefs, reactive } from "vue";
|
||||
export default {
|
||||
name: "login",
|
||||
components: { Account, Mobile },
|
||||
setup() {
|
||||
const { proxy } = getCurrentInstance();
|
||||
const state = reactive({
|
||||
tabsActiveName: "account",
|
||||
isTabPaneShow: false,
|
||||
@ -46,8 +45,8 @@ export default {
|
||||
state.isTabPaneShow = !state.isTabPaneShow;
|
||||
};
|
||||
return {
|
||||
...toRefs(state),
|
||||
onTabsClick,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
};
|
||||
@ -57,7 +56,7 @@ export default {
|
||||
.login-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url("/@/assets/bg-login.png") no-repeat;
|
||||
background: url("/src/assets/bg-login.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
.login-logo {
|
||||
position: absolute;
|
||||
@ -73,13 +72,14 @@ export default {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%) translate3d(0, 0, 0);
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 2px 12px 0 var(--color-primary-light-1);
|
||||
border-radius: 4px;
|
||||
transition: height 0.2s linear;
|
||||
height: 480px;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
.login-content-main {
|
||||
margin: 0 auto;
|
||||
width: 80%;
|
||||
@ -90,6 +90,7 @@ export default {
|
||||
text-align: center;
|
||||
letter-spacing: 4px;
|
||||
margin: 15px 0 30px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,6 +106,12 @@ export default {
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
opacity: 0.8;
|
||||
.login-copyright-company {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.login-copyright-msg {
|
||||
@extend .login-copyright-company;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user