Merge branch 'master' of https://github.com/zouzhibin/vue-admin-perfect into vue-i18n
This commit is contained in:
commit
dc2f38da43
|
|
@ -12,7 +12,7 @@ vue-element-perfect 是一个后台前端解决方案,它使用了最新的前
|
||||||
### git仓库(欢迎 Star⭐)
|
### git仓库(欢迎 Star⭐)
|
||||||
- Gitee: —— [https://gitee.com/yuanzbz/vue-admin-perfect](https://gitee.com/yuanzbz/vue-admin-perfect)
|
- Gitee: —— [https://gitee.com/yuanzbz/vue-admin-perfect](https://gitee.com/yuanzbz/vue-admin-perfect)
|
||||||
- GitHub: —— [https://github.com/zouzhibin/vue-admin-perfect](https://github.com/zouzhibin/vue-admin-perfect)
|
- GitHub: —— [https://github.com/zouzhibin/vue-admin-perfect](https://github.com/zouzhibin/vue-admin-perfect)
|
||||||
- 基础功能版本: —— [https://gitee.com/yuanzbz/vue-admin-perfect](https://gitee.com/yuanzbz/vue-admin-perfect)
|
- 基础功能版本: —— [https://gitee.com/yuanzbz/vue-admin-simple](https://gitee.com/yuanzbz/vue-admin-simple)
|
||||||
|
|
||||||
## 项目功能
|
## 项目功能
|
||||||
- 使用Vue3.0开发,单文件组件采用<script setup>
|
- 使用Vue3.0开发,单文件组件采用<script setup>
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
"pinia": "^2.0.21",
|
"pinia": "^2.0.21",
|
||||||
"pinia-plugin-persistedstate": "^2.1.1",
|
"pinia-plugin-persistedstate": "^2.1.1",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
|
"raf": "^3.4.1",
|
||||||
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
"sass": "^1.54.0",
|
"sass": "^1.54.0",
|
||||||
"splitpanes": "^3.1.1",
|
"splitpanes": "^3.1.1",
|
||||||
"svg-sprite-loader": "^6.0.11",
|
"svg-sprite-loader": "^6.0.11",
|
||||||
|
|
@ -6524,6 +6526,11 @@
|
||||||
"integrity": "sha512-x3nrPvG0HDSDzUiJ0WqtzhN4MD+h5B+dFJ3/qyxVuARlr4Y3aJv8gri2cZzp9Z8sGs2a+aG9gNbKngh3gme57A==",
|
"integrity": "sha512-x3nrPvG0HDSDzUiJ0WqtzhN4MD+h5B+dFJ3/qyxVuARlr4Y3aJv8gri2cZzp9Z8sGs2a+aG9gNbKngh3gme57A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/performance-now": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
|
|
@ -6883,6 +6890,14 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/raf": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
|
"dependencies": {
|
||||||
|
"performance-now": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-pkg": {
|
"node_modules/read-pkg": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://r2.cnpmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
"resolved": "https://r2.cnpmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
||||||
|
|
@ -7177,6 +7192,11 @@
|
||||||
"resolved": "https://registry.npmmirror.com/resize-detector/-/resize-detector-0.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/resize-detector/-/resize-detector-0.3.0.tgz",
|
||||||
"integrity": "sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ=="
|
"integrity": "sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/resize-observer-polyfill": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.1",
|
"version": "1.22.1",
|
||||||
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz",
|
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz",
|
||||||
|
|
@ -14653,6 +14673,11 @@
|
||||||
"integrity": "sha512-x3nrPvG0HDSDzUiJ0WqtzhN4MD+h5B+dFJ3/qyxVuARlr4Y3aJv8gri2cZzp9Z8sGs2a+aG9gNbKngh3gme57A==",
|
"integrity": "sha512-x3nrPvG0HDSDzUiJ0WqtzhN4MD+h5B+dFJ3/qyxVuARlr4Y3aJv8gri2cZzp9Z8sGs2a+aG9gNbKngh3gme57A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"performance-now": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||||
|
},
|
||||||
"picocolors": {
|
"picocolors": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
|
|
@ -14909,6 +14934,14 @@
|
||||||
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"raf": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
|
"requires": {
|
||||||
|
"performance-now": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://r2.cnpmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
"resolved": "https://r2.cnpmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
||||||
|
|
@ -15142,6 +15175,11 @@
|
||||||
"resolved": "https://registry.npmmirror.com/resize-detector/-/resize-detector-0.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/resize-detector/-/resize-detector-0.3.0.tgz",
|
||||||
"integrity": "sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ=="
|
"integrity": "sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ=="
|
||||||
},
|
},
|
||||||
|
"resize-observer-polyfill": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
|
||||||
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.22.1",
|
"version": "1.22.1",
|
||||||
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz",
|
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz",
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 140 KiB |
|
|
@ -27,7 +27,7 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-right:20px;
|
|
||||||
:deep(.el-menu-item){
|
:deep(.el-menu-item){
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,18 @@
|
||||||
:collapse-transition="false"
|
:collapse-transition="false"
|
||||||
class="menu-horizontal"
|
class="menu-horizontal"
|
||||||
>
|
>
|
||||||
<SubMenu :menuList="permission_routes"/>
|
<SubItem
|
||||||
|
v-for="route in permission_routes"
|
||||||
|
:key="route.path"
|
||||||
|
:item="route"
|
||||||
|
|
||||||
|
/>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
<HeaderToolRight/>
|
<HeaderToolRight/>
|
||||||
</div>
|
</div>
|
||||||
<TagsView v-if="themeConfig.showTag"/>
|
<TagsView v-if="themeConfig.showTag"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
@ -29,7 +35,7 @@
|
||||||
import Height from '../../components/Header/components/Height.vue'
|
import Height from '../../components/Header/components/Height.vue'
|
||||||
import HeaderToolRight from '../../components/Header/ToolRight.vue'
|
import HeaderToolRight from '../../components/Header/ToolRight.vue'
|
||||||
import TagsView from '../../components/TagsView/index.vue'
|
import TagsView from '../../components/TagsView/index.vue'
|
||||||
import SubMenu from '../../components/SubMenu/SubMenu.vue'
|
import SubItem from '../../components/SubMenu/SubItem.vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import {usePermissionStore} from "@/store/modules/permission"
|
||||||
const PermissionStore = usePermissionStore()
|
const PermissionStore = usePermissionStore()
|
||||||
|
|
@ -50,6 +56,7 @@ const activeMenu = computed(() => {
|
||||||
return path
|
return path
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// 主题配置
|
// 主题配置
|
||||||
const themeConfig = computed(() =>SettingStore.themeConfig)
|
const themeConfig = computed(() =>SettingStore.themeConfig)
|
||||||
const isCollapse = computed(() =>!SettingStore.isCollapse)
|
const isCollapse = computed(() =>!SettingStore.isCollapse)
|
||||||
|
|
@ -57,5 +64,6 @@ const isCollapse = computed(() =>!SettingStore.isCollapse)
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./index.scss";
|
@import "./index.scss";
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,12 @@
|
||||||
class="el-menu-vertical-demo"
|
class="el-menu-vertical-demo"
|
||||||
:collapse="isCollapse"
|
:collapse="isCollapse"
|
||||||
>
|
>
|
||||||
<SubMenu :menuList="permission_routes"/>
|
<SubItem
|
||||||
|
v-for="route in permission_routes"
|
||||||
|
:key="route.path"
|
||||||
|
:item="route"
|
||||||
|
|
||||||
|
/>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -19,10 +24,10 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import Logo from './components/Logo.vue'
|
import Logo from './components/Logo.vue'
|
||||||
import SubMenu from '../SubMenu/SubMenu.vue'
|
import SubItem from '../SubMenu/SubItem.vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import {useSettingStore} from "@/store/modules/setting"
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import {usePermissionStore} from "@/store/modules/permission"
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
// 在setup中获取store
|
// 在setup中获取store
|
||||||
|
|
@ -35,8 +40,6 @@ const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
// 设置
|
// 设置
|
||||||
const themeConfig = computed(() =>SettingStore.themeConfig )
|
const themeConfig = computed(() =>SettingStore.themeConfig )
|
||||||
|
|
||||||
const basePath = ref('/')
|
|
||||||
|
|
||||||
// 获取路由
|
// 获取路由
|
||||||
const permission_routes = computed(() => PermissionStore.permission_routes)
|
const permission_routes = computed(() => PermissionStore.permission_routes)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<component :is="type" v-bind="linkProps(to)">
|
||||||
|
<slot />
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { isExternal } from '@/utils/validate.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isExternal() {
|
||||||
|
return isExternal(this.to)
|
||||||
|
},
|
||||||
|
type() {
|
||||||
|
if (this.isExternal) {
|
||||||
|
return 'a'
|
||||||
|
}
|
||||||
|
return 'router-link'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
linkProps(to) {
|
||||||
|
if (this.isExternal) {
|
||||||
|
return {
|
||||||
|
href: to,
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noopener',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
to: to,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<template>
|
||||||
|
<template v-if="!item.hidden">
|
||||||
|
<template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
|
||||||
|
<app-link v-if="onlyOneChild.meta" :to="onlyOneChild.path">
|
||||||
|
<el-menu-item :index="onlyOneChild.path">
|
||||||
|
<el-icon :size="20">
|
||||||
|
<component :is="onlyOneChild?.meta.icon"></component>
|
||||||
|
</el-icon>
|
||||||
|
<template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>
|
||||||
|
</el-menu-item>
|
||||||
|
</app-link>
|
||||||
|
</template>
|
||||||
|
<el-sub-menu :index="item.path" v-else popper-append-to-body>
|
||||||
|
<template #title>
|
||||||
|
<el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
|
||||||
|
<span>{{ item.meta && item.meta.title }}</span>
|
||||||
|
</template>
|
||||||
|
<sub-item
|
||||||
|
v-for="child in item.children"
|
||||||
|
:key="child.path"
|
||||||
|
:item="child"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</el-sub-menu>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { isExternal } from '@/utils/validate.js'
|
||||||
|
import AppLink from './Link.vue'
|
||||||
|
import path from 'path-browserify'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
const props = defineProps({
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
basePath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const onlyOneChild = ref(null)
|
||||||
|
const hasOneShowingChild = (children = [], parent) => {
|
||||||
|
const showingChildren = children.filter((item) => {
|
||||||
|
// 过滤掉需要隐藏的菜单
|
||||||
|
if (item.hidden) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
// 临时设置(如果只有一个显示子项,则将使用)
|
||||||
|
onlyOneChild.value = item
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 当只有一个子路由器时,默认情况下会显示该子路由器
|
||||||
|
if (showingChildren.length === 1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 如果没有要显示的子路由器,则显示父路由器
|
||||||
|
if (showingChildren.length === 0) {
|
||||||
|
onlyOneChild.value = { ...parent, noShowingChildren: true }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvePath = (routePath) => {
|
||||||
|
if (isExternal(routePath)) {
|
||||||
|
return routePath
|
||||||
|
}
|
||||||
|
if (isExternal(props.basePath)) {
|
||||||
|
return props.basePath
|
||||||
|
}
|
||||||
|
return path.resolve(props.basePath, routePath)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
Loading…
Reference in New Issue