mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-25 17:22:55 +00:00
feat: 页面结构
This commit is contained in:
parent
5511769673
commit
439400d023
|
|
@ -1,17 +1,41 @@
|
|||
<template>
|
||||
<component :is="Object.keys(iconMap).includes(iconName) ? iconMap[iconName].iconReader() : iconMap['404'].iconReader()">
|
||||
<component
|
||||
v-if="isIconfont"
|
||||
:is="
|
||||
Object.keys(iconMap).includes(iconName)
|
||||
? iconMap[iconName].iconReader()
|
||||
: iconMap['404'].iconReader()
|
||||
"
|
||||
class="app-icon"
|
||||
>
|
||||
</component>
|
||||
<el-icon v-else-if="iconName">
|
||||
<component :is="iconName" />
|
||||
</el-icon>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { iconMap } from "@/components/icons/index"
|
||||
defineOptions({ name: 'AppIcon' });
|
||||
withDefaults(defineProps<{
|
||||
iconName?: string;
|
||||
}>(), {
|
||||
iconName: '404'
|
||||
});
|
||||
|
||||
import { computed } from 'vue'
|
||||
import { iconMap } from '@/components/icons/index'
|
||||
defineOptions({ name: 'AppIcon' })
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
iconName?: string
|
||||
}>(),
|
||||
{
|
||||
iconName: '404'
|
||||
}
|
||||
)
|
||||
|
||||
const isIconfont = computed(() => props.iconName?.includes('app-'))
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-icon {
|
||||
line-height: 1em;
|
||||
svg {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { h } from 'vue'
|
||||
export const iconMap: any = {
|
||||
'404': {
|
||||
'app-404': {
|
||||
iconReader: () => {
|
||||
return h('el-icon', { style: 'display:flex' }, [
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
|
|
@ -33,131 +33,62 @@ export const iconMap: any = {
|
|||
])
|
||||
}
|
||||
},
|
||||
home: {
|
||||
|
||||
'app-dataset': {
|
||||
iconReader: () => {
|
||||
return h('el-icon', { style: 'display:flex' }, [
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
style: 'height:14px;width:14px',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M362.666667 895.914667V639.850667c0-36.266667 33.109333-63.850667 72.533333-63.850667h153.6c39.253333 0 72.533333 27.648 72.533333 63.850667v256.064h59.904c61.269333 0 110.762667-47.957333 110.762667-106.730667V414.165333L557.162667 139.328a63.808 63.808 0 0 0-90.325334 0L192 414.165333v375.018667c0 58.88 49.386667 106.730667 110.762667 106.730667H362.666667z m42.666666 0h213.333334V639.850667c0-10.709333-12.586667-21.184-29.866667-21.184h-153.6c-17.408 0-29.866667 10.389333-29.866667 21.184v256.064z m469.333334-439.082667v332.352c0 82.645333-68.885333 149.397333-153.429334 149.397333H302.762667C218.133333 938.581333 149.333333 871.936 149.333333 789.184V456.832l-27.584 27.584a21.333333 21.333333 0 1 1-30.165333-30.165333L436.672 109.162667a106.474667 106.474667 0 0 1 150.656 0l345.088 345.088a21.333333 21.333333 0 0 1-30.165333 30.165333L874.666667 456.832z',
|
||||
fill: '#666666'
|
||||
})
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
||||
},
|
||||
app: {
|
||||
iconReader: () => {
|
||||
return h('el-icon', { style: 'display:flex' }, [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
style: 'height:14px;width:14px',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M906.62890625 212.8203125C906.62890625 161.58007812 865.05664063 120.0078125 813.81640625 120.0078125H645.2421875C594.00195313 120.0078125 552.4296875 161.58007812 552.4296875 212.8203125v168.57421875c0 51.24023438 41.57226563 92.8125 92.8125 92.8125h168.57421875c51.24023438 0 92.8125-41.57226563 92.8125-92.8125V212.8203125z m-56.25 173.93554688c0 17.05078125-28.125 31.20117188-45.26367188 31.20117187H640.3203125c-17.05078125 0-30.76171875-14.0625-30.76171875-31.20117188V207.81054687c0-17.05078125 13.7109375-30.67382813 30.76171875-30.67382812h178.9453125c17.05078125 0 31.02539063 13.62304688 31.02539063 30.67382813v178.94531249z m56.25 251.45507812c0-51.24023438-41.57226563-92.8125-92.8125-92.8125H645.2421875C594.00195313 545.3984375 552.4296875 586.97070313 552.4296875 638.2109375v168.57421875c0 51.24023438 41.57226563 92.8125 92.8125 92.8125h168.57421875c51.24023438 0 92.8125-41.57226563 92.8125-92.8125V638.2109375z m-56.25 173.3203125c0 17.05078125-13.88671875 30.9375-30.9375 30.9375H640.49609375c-17.05078125 0-30.9375-13.88671875-30.9375-30.9375V632.5859375c0-17.05078125 13.88671875-30.9375 30.9375-30.9375h178.9453125c17.05078125 0 30.9375 13.88671875 30.9375 30.9375v178.9453125zM468.0546875 638.2109375c0-51.24023438-41.57226563-92.8125-92.8125-92.8125H206.66796875C155.42773437 545.3984375 113.85546875 586.97070313 113.85546875 638.2109375v168.57421875C113.85546875 858.02539063 155.42773437 899.59765625 206.66796875 899.59765625h168.57421875c51.24023438 0 92.8125-41.57226563 92.8125-92.8125V638.2109375z m-57.12890625 173.3203125c0 17.05078125-13.88671875 30.9375-30.9375 30.9375H201.04296875c-17.05078125 0-30.9375-13.88671875-30.9375-30.9375V632.5859375c0-17.05078125 13.88671875-30.9375 30.9375-30.9375h178.9453125c17.05078125 0 30.9375 13.88671875 30.9375 30.9375v178.9453125z m57.12890625-598.7109375C468.0546875 161.58007812 426.48242187 120.0078125 375.2421875 120.0078125H206.66796875C155.42773437 120.0078125 113.85546875 161.58007812 113.85546875 212.8203125v168.57421875C113.85546875 432.63476562 155.42773437 474.20703125 206.66796875 474.20703125h168.57421875c51.24023438 0 92.8125-41.57226563 92.8125-92.8125V212.8203125z m-57.12890625 174.19921875c0 17.05078125-13.88671875 30.9375-30.9375 30.9375H201.04296875c-17.05078125 0-30.9375-13.88671875-30.9375-30.9375V208.07421875c0-17.05078125 13.88671875-30.9375 30.9375-30.9375h178.9453125c17.05078125 0 30.9375 13.88671875 30.9375 30.9375v178.9453125z',
|
||||
fill: '#768696'
|
||||
})
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
||||
},
|
||||
dataset: {
|
||||
iconReader: () => {
|
||||
return h('el-icon', { style: 'display:flex' }, [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
style: 'height:14px;width:14px',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M859.5 193H446.939c-1.851-53.25-45.747-96-99.439-96h-183C109.635 97 65 141.635 65 196.5v632c0 54.864 44.635 99.5 99.5 99.5h695c54.864 0 99.5-44.636 99.5-99.5v-536c0-54.865-44.636-99.5-99.5-99.5z m-695-33h183c20.126 0 36.5 16.374 36.5 36.5v28c0 17.397 14.103 31.5 31.5 31.5h444c20.126 0 36.5 16.374 36.5 36.5V321H128V196.5c0-20.126 16.374-36.5 36.5-36.5z m695 705h-695c-20.126 0-36.5-16.374-36.5-36.5V384h768v444.5c0 20.126-16.374 36.5-36.5 36.5z',
|
||||
fill: '#070102'
|
||||
fill: 'currentColor'
|
||||
})
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
||||
},
|
||||
setting: {
|
||||
'app-applicaiton': {
|
||||
iconReader: () => {
|
||||
return h('el-icon', { style: 'display:flex' }, [
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
style: 'height:14px;width:14px',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M512 328c-100.8 0-184 83.2-184 184S411.2 696 512 696 696 612.8 696 512 612.8 328 512 328z m0 320c-75.2 0-136-60.8-136-136s60.8-136 136-136 136 60.8 136 136-60.8 136-136 136z',
|
||||
fill: '#070102'
|
||||
}),
|
||||
h('path', {
|
||||
d: 'M857.6 572.8c-20.8-12.8-33.6-35.2-33.6-60.8s12.8-46.4 33.6-60.8c14.4-9.6 20.8-27.2 16-44.8-8-27.2-19.2-52.8-32-76.8-8-14.4-25.6-24-43.2-19.2-24 4.8-48-1.6-65.6-19.2-17.6-17.6-24-41.6-19.2-65.6 3.2-16-4.8-33.6-19.2-43.2-24-14.4-51.2-24-76.8-32-16-4.8-35.2 1.6-44.8 16-12.8 20.8-35.2 33.6-60.8 33.6s-46.4-12.8-60.8-33.6c-9.6-14.4-27.2-20.8-44.8-16-27.2 8-52.8 19.2-76.8 32-14.4 8-24 25.6-19.2 43.2 4.8 24-1.6 49.6-19.2 65.6-17.6 17.6-41.6 24-65.6 19.2-16-3.2-33.6 4.8-43.2 19.2-14.4 24-24 51.2-32 76.8-4.8 16 1.6 35.2 16 44.8 20.8 12.8 33.6 35.2 33.6 60.8s-12.8 46.4-33.6 60.8c-14.4 9.6-20.8 27.2-16 44.8 8 27.2 19.2 52.8 32 76.8 8 14.4 25.6 22.4 43.2 19.2 24-4.8 49.6 1.6 65.6 19.2 17.6 17.6 24 41.6 19.2 65.6-3.2 16 4.8 33.6 19.2 43.2 24 14.4 51.2 24 76.8 32 16 4.8 35.2-1.6 44.8-16 12.8-20.8 35.2-33.6 60.8-33.6s46.4 12.8 60.8 33.6c8 11.2 20.8 17.6 33.6 17.6 3.2 0 8 0 11.2-1.6 27.2-8 52.8-19.2 76.8-32 14.4-8 24-25.6 19.2-43.2-4.8-24 1.6-49.6 19.2-65.6 17.6-17.6 41.6-24 65.6-19.2 16 3.2 33.6-4.8 43.2-19.2 14.4-24 24-51.2 32-76.8 4.8-17.6-1.6-35.2-16-44.8z m-56 92.8c-38.4-6.4-76.8 6.4-104 33.6-27.2 27.2-40 65.6-33.6 104-17.6 9.6-36.8 17.6-56 24-22.4-30.4-57.6-49.6-97.6-49.6-38.4 0-73.6 17.6-97.6 49.6-19.2-6.4-38.4-14.4-56-24 6.4-38.4-6.4-76.8-33.6-104-27.2-27.2-65.6-40-104-33.6-9.6-17.6-17.6-36.8-24-56 30.4-22.4 49.6-57.6 49.6-97.6 0-38.4-17.6-73.6-49.6-97.6 6.4-19.2 14.4-38.4 24-56 38.4 6.4 76.8-6.4 104-33.6 27.2-27.2 40-65.6 33.6-104 17.6-9.6 36.8-17.6 56-24 22.4 30.4 57.6 49.6 97.6 49.6 38.4 0 73.6-17.6 97.6-49.6 19.2 6.4 38.4 14.4 56 24-6.4 38.4 6.4 76.8 33.6 104 27.2 27.2 65.6 40 104 33.6 9.6 17.6 17.6 36.8 24 56-30.4 22.4-49.6 57.6-49.6 97.6 0 38.4 17.6 73.6 49.6 97.6-6.4 19.2-14.4 38.4-24 56z',
|
||||
fill: '#070102'
|
||||
d: 'M951.901 244.015l-413.3-238.57a33.606 33.606 0 0 0-33.909 0L91.3 244.016c-10.426 6.12-16.99 17.221-16.99 29.346v477.184c0 12.149 6.447 23.343 16.99 29.37l413.3 238.662c5.213 2.933 11.101 4.515 16.99 4.515 5.794 0 11.775-1.582 16.988-4.515l413.3-238.661c10.427-6.121 16.99-17.222 16.99-29.37V273.36a33.908 33.908 0 0 0-16.966-29.346zM892.23 726.016l-370.618 213.97-370.642-213.97v-427.87L521.588 84.178l370.642 213.97v427.869z m8.797 5.073M285.207 348.393a34.095 34.095 0 0 0-46.336 12.567 33.908 33.908 0 0 0 12.474 46.36l235.94 136.215v269.498a33.745 33.745 0 0 0 33.884 33.885 33.745 33.745 0 0 0 33.886-33.885V543.977L791.9 407.227a34.025 34.025 0 0 0 12.451-46.36 34.025 34.025 0 0 0-46.336-12.474l-236.404 136.54-236.405-136.54z m0 0',
|
||||
fill: 'currentColor'
|
||||
})
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
||||
},
|
||||
password: {
|
||||
|
||||
'app-exit': {
|
||||
iconReader: () => {
|
||||
return h('el-icon', { style: 'display:flex' }, [
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
style: 'height:14px;width:14px',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M807.28626 393.9647l-59.057047 0 0-78.729086c0-130.193201-105.96438-236.099253-236.229213-236.099253S275.770787 185.042413 275.770787 315.235614l0 78.729086-59.057047 0c-32.616862 0-59.057047 26.425859-59.057047 59.025325L157.656693 885.838314c0 32.598442 26.441209 59.025325 59.057047 59.025325l590.57252 0c32.616862 0 59.057047-26.425859 59.057047-59.025325L866.343307 452.989001C866.343307 420.390559 839.903122 393.9647 807.28626 393.9647zM334.827835 315.235614c0-97.644901 79.473029-177.074951 177.172165-177.074951s177.172165 79.43005 177.172165 177.074951l0 78.729086L334.827835 393.9647 334.827835 315.235614zM807.28626 885.838314 216.71374 885.838314 216.71374 452.989001l590.57252 0L807.28626 885.838314z'
|
||||
}),
|
||||
h('path', {
|
||||
d: 'M512 777.635963c16.302291 0 29.528524-13.219069 29.528524-29.512151L541.528524 590.723969c0-16.293081-13.226233-29.512151-29.528524-29.512151s-29.528524 13.219069-29.528524 29.512151l0 157.399843C482.471476 764.416893 495.697709 777.635963 512 777.635963z'
|
||||
})
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
||||
},
|
||||
exit: {
|
||||
iconReader: () => {
|
||||
return h('el-icon', { style: 'display:flex' }, [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
style: 'height:14px;width:14px',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M874.666667 855.744a19.093333 19.093333 0 0 1-19.136 18.922667H168.469333A19.2 19.2 0 0 1 149.333333 855.530667V168.469333A19.2 19.2 0 0 1 168.469333 149.333333h687.061334c10.581333 0 19.136 8.533333 19.136 18.922667V320h42.666666V168.256A61.717333 61.717333 0 0 0 855.530667 106.666667H168.469333A61.866667 61.866667 0 0 0 106.666667 168.469333v687.061334A61.866667 61.866667 0 0 0 168.469333 917.333333h687.061334A61.76 61.76 0 0 0 917.333333 855.744V704h-42.666666v151.744zM851.84 533.333333l-131.797333 131.754667a21.141333 21.141333 0 0 0 0.213333 29.973333 21.141333 21.141333 0 0 0 29.973333 0.192l165.589334-165.589333a20.821333 20.821333 0 0 0 6.122666-14.976 21.44 21.44 0 0 0-6.314666-14.997333l-168.533334-168.533334a21.141333 21.141333 0 0 0-29.952-0.213333 21.141333 21.141333 0 0 0 0.213334 29.973333L847.296 490.666667H469.333333v42.666666h382.506667z'
|
||||
d: 'M874.666667 855.744a19.093333 19.093333 0 0 1-19.136 18.922667H168.469333A19.2 19.2 0 0 1 149.333333 855.530667V168.469333A19.2 19.2 0 0 1 168.469333 149.333333h687.061334c10.581333 0 19.136 8.533333 19.136 18.922667V320h42.666666V168.256A61.717333 61.717333 0 0 0 855.530667 106.666667H168.469333A61.866667 61.866667 0 0 0 106.666667 168.469333v687.061334A61.866667 61.866667 0 0 0 168.469333 917.333333h687.061334A61.76 61.76 0 0 0 917.333333 855.744V704h-42.666666v151.744zM851.84 533.333333l-131.797333 131.754667a21.141333 21.141333 0 0 0 0.213333 29.973333 21.141333 21.141333 0 0 0 29.973333 0.192l165.589334-165.589333a20.821333 20.821333 0 0 0 6.122666-14.976 21.44 21.44 0 0 0-6.314666-14.997333l-168.533334-168.533334a21.141333 21.141333 0 0 0-29.952-0.213333 21.141333 21.141333 0 0 0 0.213334 29.973333L847.296 490.666667H469.333333v42.666666h382.506667z',
|
||||
fill: 'currentColor'
|
||||
})
|
||||
]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onBeforeUpdate } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import TopBar from '@/components/layout/top-bar/index.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const cachedViews: any = ref([])
|
||||
|
||||
onBeforeUpdate(() => {
|
||||
let isCached = route.meta?.cache
|
||||
let name = route.name
|
||||
if (isCached && name && !cachedViews.value.includes(name)) {
|
||||
cachedViews.value.push(name)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-layout">
|
||||
<div class="app-header">
|
||||
<TopBar></TopBar>
|
||||
</div>
|
||||
<div class="app-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition appear name="fade-transform" mode="out-in">
|
||||
<keep-alive :include="cachedViews">
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.app-main {
|
||||
height: calc(100vh - var(--app-header-height));
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import TopBar from "@/components/layout/top-bar/index.vue"
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="common-layout">
|
||||
<el-container>
|
||||
<el-header>
|
||||
<TopBar></TopBar>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<RouterView></RouterView>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.el-header {
|
||||
--el-header-padding: 0;
|
||||
--el-header-height: 56px;
|
||||
padding: var(--el-header-padding);
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
height: var(--el-header-height);
|
||||
}
|
||||
|
||||
.el-main {
|
||||
--el-main-padding: 0;
|
||||
width: 100vw;
|
||||
height: calc(100vh - var(--el-header-height, 60px));
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,155 +1,176 @@
|
|||
<template >
|
||||
<el-dialog v-model="resetPasswordDialog" title="修改密码">
|
||||
<el-form class="reset-password-form" ref="resetPasswordFormRef" :model="resetPasswordForm" :rules="rules">
|
||||
|
||||
<el-form-item prop="password">
|
||||
<el-input type="password" size="large" class="input-item" v-model="resetPasswordForm.password"
|
||||
placeholder="请输入密码">
|
||||
|
||||
<template #prepend>
|
||||
<el-button :icon="Lock" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="re_password">
|
||||
<el-input type="password" size="large" class="input-item" v-model="resetPasswordForm.re_password"
|
||||
placeholder="请输入确认密码">
|
||||
<template #prepend>
|
||||
<el-button :icon="Lock" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input size="large" class="input-item" :disabled="true" v-bind:modelValue="userStore.userInfo?.email"
|
||||
@change="() => { }" placeholder="请输入邮箱">
|
||||
|
||||
<template #prepend>
|
||||
<el-button :icon="UserFilled" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-input size="large" class="code-input" v-model="resetPasswordForm.code" placeholder="请输入验证码">
|
||||
<template #prepend>
|
||||
<el-button :icon="Key" />
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button size="large" class="send-email-button" @click="sendEmail" :loading="loading">获取验证码</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="resetPassword">
|
||||
修改密码
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template>
|
||||
<el-dialog v-model="resetPasswordDialog" title="修改密码">
|
||||
<el-form
|
||||
class="reset-password-form"
|
||||
ref="resetPasswordFormRef"
|
||||
:model="resetPasswordForm"
|
||||
:rules="rules"
|
||||
>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
type="password"
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.password"
|
||||
placeholder="请输入密码"
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button icon="Lock" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="re_password">
|
||||
<el-input
|
||||
type="password"
|
||||
size="large"
|
||||
class="input-item"
|
||||
v-model="resetPasswordForm.re_password"
|
||||
placeholder="请输入确认密码"
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button icon="Lock" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input
|
||||
size="large"
|
||||
class="input-item"
|
||||
:disabled="true"
|
||||
v-bind:modelValue="userStore.userInfo?.email"
|
||||
@change="() => {}"
|
||||
placeholder="请输入邮箱"
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button icon="UserFilled" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<div class="flex-between w-full">
|
||||
<el-input
|
||||
size="large"
|
||||
class="code-input"
|
||||
v-model="resetPasswordForm.code"
|
||||
placeholder="请输入验证码"
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button icon="Key" />
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button
|
||||
size="large"
|
||||
class="send-email-button ml-1"
|
||||
@click="sendEmail"
|
||||
:loading="loading"
|
||||
>获取验证码</el-button
|
||||
>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="resetPassword"> 修改密码 </el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import type { ResetCurrentUserPasswordRequest } from "@/api/user/type";
|
||||
import { ref } from 'vue'
|
||||
import type { ResetCurrentUserPasswordRequest } from '@/api/user/type'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { ElMessage } from "element-plus"
|
||||
import UserApi from "@/api/user"
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { Lock, UserFilled, Key } from '@element-plus/icons-vue'
|
||||
import { useRouter } from "vue-router"
|
||||
const router = useRouter();
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import UserApi from '@/api/user'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const resetPasswordDialog = ref<boolean>(false);
|
||||
const resetPasswordDialog = ref<boolean>(false)
|
||||
|
||||
const resetPasswordForm = ref<ResetCurrentUserPasswordRequest>({
|
||||
code: "",
|
||||
password: "",
|
||||
re_password: ""
|
||||
});
|
||||
code: '',
|
||||
password: '',
|
||||
re_password: ''
|
||||
})
|
||||
|
||||
const resetPasswordFormRef = ref<FormInstance>();
|
||||
const resetPasswordFormRef = ref<FormInstance>()
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
const rules = ref<FormRules<ResetCurrentUserPasswordRequest>>({
|
||||
|
||||
code: [
|
||||
{ required: true, message: '请输入验证码' }
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入密码",
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: "长度在 6 到 30 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
re_password: [{
|
||||
required: true,
|
||||
message: '请输入确认密码',
|
||||
trigger: 'blur'
|
||||
code: [{ required: true, message: '请输入验证码' }],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: "长度在 6 到 30 个字符",
|
||||
trigger: "blur",
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: '长度在 6 到 30 个字符',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
re_password: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入确认密码',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
||||
callback(new Error('密码不一致'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}]
|
||||
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: '长度在 6 到 30 个字符',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (resetPasswordForm.value.password != resetPasswordForm.value.re_password) {
|
||||
callback(new Error('密码不一致'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
/**
|
||||
* 发送验证码
|
||||
*/
|
||||
const sendEmail = () => {
|
||||
UserApi.sendEmailToCurrent(loading)
|
||||
.then(() => {
|
||||
ElMessage.success("发送验证码成功")
|
||||
})
|
||||
|
||||
UserApi.sendEmailToCurrent(loading).then(() => {
|
||||
MsgSuccess('发送验证码成功')
|
||||
})
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
resetPasswordForm.value = {
|
||||
code: "",
|
||||
password: "",
|
||||
re_password: ""
|
||||
}
|
||||
resetPasswordDialog.value = true
|
||||
resetPasswordForm.value = {
|
||||
code: '',
|
||||
password: '',
|
||||
re_password: ''
|
||||
}
|
||||
resetPasswordDialog.value = true
|
||||
}
|
||||
const resetPassword = () => {
|
||||
resetPasswordFormRef.value?.validate().then(() => {
|
||||
return UserApi.resetCurrentUserPassword(resetPasswordForm.value)
|
||||
}).then(() => {
|
||||
return userStore.logout()
|
||||
}).then(() => {
|
||||
router.push({ name: 'login' })
|
||||
resetPasswordFormRef.value
|
||||
?.validate()
|
||||
.then(() => {
|
||||
return UserApi.resetCurrentUserPassword(resetPasswordForm.value)
|
||||
})
|
||||
.then(() => {
|
||||
return userStore.logout()
|
||||
})
|
||||
.then(() => {
|
||||
router.push({ name: 'login' })
|
||||
})
|
||||
}
|
||||
const close = () => { resetPasswordDialog.value = false }
|
||||
const close = () => {
|
||||
resetPasswordDialog.value = false
|
||||
}
|
||||
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.code-input {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.send-email-button {
|
||||
margin-left: 12px;
|
||||
width: 158px;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scope></style>
|
||||
|
|
|
|||
|
|
@ -1,50 +1,39 @@
|
|||
<template >
|
||||
<el-dropdown trigger="click" size="small" type="primary">
|
||||
<el-avatar> {{ firstUserName }} </el-avatar>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openResetPassword">
|
||||
<AppIcon iconName="password"></AppIcon><span style="margin-left:5px">修改密码</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="logout">
|
||||
<AppIcon iconName="exit"></AppIcon><span style="margin-left:5px">退出</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<ResetPassword ref="resetPasswordRef"></ResetPassword>
|
||||
<template>
|
||||
<el-dropdown trigger="click" type="primary">
|
||||
<el-avatar :size="30"> {{ firstUserName }} </el-avatar>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openResetPassword">
|
||||
<AppIcon iconName="Lock"></AppIcon><span style="margin-left: 5px">修改密码</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="logout">
|
||||
<AppIcon iconName="app-exit"></AppIcon><span style="margin-left: 5px">退出</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<ResetPassword ref="resetPasswordRef"></ResetPassword>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { useRouter } from "vue-router";
|
||||
import AppIcon from "@/components/icons/AppIcon.vue"
|
||||
import ResetPassword from "@/components/layout/top-bar/components/avatar/ResetPasssword.vue"
|
||||
import { computed, ref } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useRouter } from 'vue-router'
|
||||
import ResetPassword from '@/components/layout/top-bar/components/avatar/ResetPasssword.vue'
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
const firstUserName = computed(() => {
|
||||
return userStore.userInfo?.username?.substring(0, 1)
|
||||
return userStore.userInfo?.username?.substring(0, 1)
|
||||
})
|
||||
const resetPasswordRef = ref<InstanceType<typeof ResetPassword>>();
|
||||
const resetPasswordRef = ref<InstanceType<typeof ResetPassword>>()
|
||||
|
||||
const openResetPassword = () => {
|
||||
resetPasswordRef.value?.open()
|
||||
resetPasswordRef.value?.open()
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
userStore.logout().then(() => {
|
||||
router.push({ name: "login" })
|
||||
})
|
||||
userStore.logout().then(() => {
|
||||
router.push({ name: 'login' })
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-avatar {
|
||||
--el-avatar-size: 30px;
|
||||
--el-avatar-bg-color: var(--app-base-action-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.el-dropdown-menu--small {
|
||||
padding: 10px 0;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,40 +1,46 @@
|
|||
<template>
|
||||
<div class="menu-item-container" :class="isActive ? 'active' : ''" @click="router.push({ name: menu.name })">
|
||||
<div class="icon">
|
||||
<AppIcon :iconName="menu.meta ? menu.meta.icon as string : '404'"></AppIcon>
|
||||
</div>
|
||||
<div class="title">{{ menu.meta?.title }} </div>
|
||||
<div
|
||||
class="menu-item-container flex-center h-full"
|
||||
:class="isActive ? 'active' : ''"
|
||||
@click="router.push({ name: menu.name })"
|
||||
>
|
||||
<div class="icon">
|
||||
<AppIcon :iconName="menu.meta ? (menu.meta.icon as string) : '404'" />
|
||||
</div>
|
||||
<div class="title">{{ menu.meta?.title }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useRouter, useRoute, type RouteRecordRaw } from 'vue-router'
|
||||
import { computed } from "vue";
|
||||
import AppIcon from "@/components/icons/AppIcon.vue"
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
import { computed } from 'vue'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const props = defineProps<{
|
||||
menu: RouteRecordRaw
|
||||
menu: RouteRecordRaw
|
||||
}>()
|
||||
|
||||
const isActive = computed(() => {
|
||||
return route.name == props.menu.name && route.path == props.menu.path
|
||||
return route.name == props.menu.name && route.path == props.menu.path
|
||||
})
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.menu-item-container {
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
|
||||
padding: 0 20px;
|
||||
cursor: pointer;
|
||||
.icon {
|
||||
font-size: 15px;
|
||||
margin-right: 5px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: var(--app-base-text-hover-bg-color);
|
||||
border-bottom: 3px solid var(--app-base-text-hover-color);
|
||||
height: calc(100% - 3px);
|
||||
font-weight: 600;
|
||||
color: var(--el-color-primary);
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
border-bottom: 3px solid var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,25 @@
|
|||
<template >
|
||||
<div class="top-menu-container">
|
||||
<MenuItem :menu="menu" v-hasPermission="menu.meta?.permission" v-for="(menu, index) in topMenuList" :key="index">
|
||||
</MenuItem>
|
||||
</div>
|
||||
<template>
|
||||
<div class="top-menu-container flex h-full">
|
||||
<MenuItem
|
||||
:menu="menu"
|
||||
v-hasPermission="menu.meta?.permission"
|
||||
v-for="(menu, index) in topMenuList"
|
||||
:key="index"
|
||||
>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { getChildRouteListByPathAndName } from "@/router/index"
|
||||
import MenuItem from "@/components/layout/top-bar/components/top-menu/MenuItem.vue"
|
||||
import { computed } from 'vue'
|
||||
import { getChildRouteListByPathAndName } from '@/router/index'
|
||||
import MenuItem from '@/components/layout/top-bar/components/top-menu/MenuItem.vue'
|
||||
const topMenuList = computed(() => {
|
||||
return getChildRouteListByPathAndName("/", "home")
|
||||
return getChildRouteListByPathAndName('/', 'home')
|
||||
})
|
||||
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.top-menu-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
<template>
|
||||
<div class="top-bar-container">
|
||||
<div class="app-title-container">
|
||||
<div class="app-title-icon"></div>
|
||||
<div class="app-title-text">{{ defaultTitle }}</div>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
<div class="app-top-menu-container">
|
||||
<div class="top-bar-container flex-between">
|
||||
<div class="flex-center h-full">
|
||||
<div class="app-title-container flex-center">
|
||||
<div class="app-title-icon"></div>
|
||||
<div class="app-title-text ml-1">{{ defaultTitle }}</div>
|
||||
</div>
|
||||
<el-divider direction="vertical" class="line" />
|
||||
<TopMenu></TopMenu>
|
||||
</div>
|
||||
<div class="flex-auto"></div>
|
||||
<div class="avatar">
|
||||
<Avatar></Avatar>
|
||||
</div>
|
||||
|
|
@ -22,31 +21,12 @@ const defaultTitle = import.meta.env.VITE_APP_TITLE
|
|||
<style lang="scss">
|
||||
.top-bar-container {
|
||||
border-bottom: 1px solid rgba(229, 229, 229, 1);
|
||||
height: calc(100% - 1px);
|
||||
background-color: var(--app-header-background-color, #fff);
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
|
||||
.flex-auto {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 100%;
|
||||
width: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
height: var(--app-header-height);
|
||||
box-sizing: border-box;
|
||||
padding: var(--app-header-padding);
|
||||
|
||||
.app-title-container {
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
margin-right: 30px;
|
||||
.app-title-icon {
|
||||
background-image: url('@/assets/logo.png');
|
||||
background-size: 100% 100%;
|
||||
|
|
@ -55,18 +35,13 @@ const defaultTitle = import.meta.env.VITE_APP_TITLE
|
|||
}
|
||||
|
||||
.app-title-text {
|
||||
color: var(--app-base-action-text-color);
|
||||
color: var(--el-color-primary);
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 60%;
|
||||
width: 1px;
|
||||
margin-left: 20px;
|
||||
background-color: rgba(229, 229, 229, 1);
|
||||
}
|
||||
}
|
||||
.line {
|
||||
height: 2em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { App } from 'vue'
|
||||
import { hasPermission } from '@/common/permission'
|
||||
import { hasPermission } from '@/utils/permission'
|
||||
|
||||
const display = async (el: any, binding: any) => {
|
||||
const has = hasPermission(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios, { type AxiosRequestConfig } from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { MsgError } from '@/utils/message'
|
||||
import type { NProgress } from 'nprogress'
|
||||
import type { Ref } from 'vue'
|
||||
import type { Result } from '@/request/Result'
|
||||
|
|
@ -41,7 +41,7 @@ instance.interceptors.response.use(
|
|||
(response: any) => {
|
||||
if (response.data) {
|
||||
if (response.data.code !== 200 && !(response.data instanceof Blob)) {
|
||||
ElMessage.error(response.data.message)
|
||||
MsgError(response.data.message)
|
||||
}
|
||||
}
|
||||
if (response.headers['content-type'] === 'application/octet-stream') {
|
||||
|
|
@ -51,7 +51,7 @@ instance.interceptors.response.use(
|
|||
},
|
||||
(err: any) => {
|
||||
if (err.code === 'ECONNABORTED') {
|
||||
ElMessage.error(err.message)
|
||||
MsgError(err.message)
|
||||
console.error(err)
|
||||
}
|
||||
if (err.response?.status === 401) {
|
||||
|
|
@ -59,7 +59,7 @@ instance.interceptors.response.use(
|
|||
}
|
||||
|
||||
if (err.response?.status === 403) {
|
||||
ElMessage.error(
|
||||
MsgError(
|
||||
err.response.data && err.response.data.message ? err.response.data.message : '没有权限访问'
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { hasPermission } from '@/common/permission/index'
|
||||
import { hasPermission } from '@/utils/permission/index'
|
||||
import {
|
||||
createRouter,
|
||||
createWebHistory,
|
||||
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { store } from '@/stores'
|
||||
import { routes } from '@/router/data'
|
||||
import { routes } from '@/router/routes'
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: routes
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
const applicationRouter = {
|
||||
path: '/app',
|
||||
name: 'app',
|
||||
meta: { icon: 'app-applicaiton', title: '应用', permission: 'APPLICATION:READ' },
|
||||
component: () => import('@/views/app/index.vue')
|
||||
}
|
||||
|
||||
export default applicationRouter
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
const datasetRouter = {
|
||||
path: '/dataset',
|
||||
name: 'dataset',
|
||||
meta: { icon: 'app-dataset', title: '数据集', permission: 'DATASET:READ' },
|
||||
component: () => import('@/views/dataset/index.vue')
|
||||
}
|
||||
|
||||
export default datasetRouter
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
const settingRouter = {
|
||||
path: '/setting',
|
||||
name: 'setting',
|
||||
meta: { icon: 'Setting', title: '系统设置', permission: 'SETTING:READ' },
|
||||
component: () => import('@/views/setting/index.vue')
|
||||
}
|
||||
|
||||
export default settingRouter
|
||||
|
|
@ -1,35 +1,22 @@
|
|||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { Role } from '@/common/permission/type'
|
||||
import { Role } from '@/utils/permission/type'
|
||||
|
||||
const modules: any = import.meta.glob('./modules/*.ts', { eager: true })
|
||||
const rolesRoutes: RouteRecordRaw[] = [...Object.keys(modules).map((key) => modules[key].default)]
|
||||
|
||||
export const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: () => import('@/components/layout/home-layout/index.vue'),
|
||||
component: () => import('@/components/layout/app-layout/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/first',
|
||||
name: 'first',
|
||||
meta: { icon: 'app', title: '首页' },
|
||||
meta: { icon: 'House', title: '首页' },
|
||||
component: () => import('@/views/first/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/app',
|
||||
name: 'app',
|
||||
meta: { icon: 'app', title: '应用', permission: 'APPLICATION:READ' },
|
||||
component: () => import('@/views/app/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/dataset',
|
||||
name: 'dataset',
|
||||
meta: { icon: 'dataset', title: '数据集', permission: 'DATASET:READ' },
|
||||
component: () => import('@/views/dataset/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/setting',
|
||||
name: 'setting',
|
||||
meta: { icon: 'setting', title: '系统设置', permission: 'SETTING:READ' },
|
||||
component: () => import('@/views/setting/index.vue')
|
||||
}
|
||||
...rolesRoutes
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -9,15 +9,11 @@ html {
|
|||
}
|
||||
|
||||
body {
|
||||
font-family:
|
||||
Helvetica,
|
||||
PingFang SC,
|
||||
Arial,
|
||||
sans-serif;
|
||||
font-size: 14px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
|
||||
'微软雅黑', Arial, sans-serif;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
@ -95,6 +91,10 @@ ul {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
.el-avatar {
|
||||
--el-avatar-bg-color: var(--el-color-primary);
|
||||
--el-avatar-size-small: 33px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.el-popper {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
|
@ -5,24 +10,22 @@
|
|||
.el-form {
|
||||
--el-form-inline-content-width: 100%;
|
||||
}
|
||||
|
||||
|
||||
// 抽屉样式整体修改
|
||||
.el-drawer{
|
||||
|
||||
.el-drawer__header{
|
||||
padding: 0;
|
||||
margin: 0 24px;
|
||||
height: 56px;
|
||||
border-bottom: 1px solid #D5D6D8;
|
||||
.el-drawer__title {
|
||||
.el-drawer {
|
||||
.el-drawer__header {
|
||||
padding: 0;
|
||||
margin: 0 24px;
|
||||
height: 56px;
|
||||
border-bottom: 1px solid #d5d6d8;
|
||||
.el-drawer__title {
|
||||
color: #1f2329;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
}
|
||||
.el-drawer__body{
|
||||
--el-drawer-padding-primary:24px
|
||||
.el-drawer__body {
|
||||
--el-drawer-padding-primary: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
:root{
|
||||
--app-base-text-color:rgba(31, 35, 41, 1);
|
||||
--app-base-text-font-size:14px;
|
||||
--app-base-text-hover-color:rgba(51, 112, 255, 1);
|
||||
--app-base-text-hover-bg-color:rgba(51, 112, 255, 0.1);
|
||||
--app-base-action-text-color:var(--app-base-text-hover-color );
|
||||
/** header 组件 */
|
||||
--app-header-height: 56px;
|
||||
--app-header-padding: 0 20px;
|
||||
--app-header-bg-color: #252b3c;
|
||||
:root {
|
||||
--el-color-primary: rgba(51, 112, 255, 1);
|
||||
--app-base-text-color: rgba(31, 35, 41, 1);
|
||||
--app-base-text-font-size: 14px;
|
||||
--app-base-text-hover-color: rgba(51, 112, 255, 1);
|
||||
--app-base-text-hover-bg-color: rgba(51, 112, 255, 0.1);
|
||||
--app-base-action-text-color: var(--app-base-text-hover-color);
|
||||
/** header 组件 */
|
||||
--app-header-height: 56px;
|
||||
--app-header-padding: 0 20px;
|
||||
--app-header-bg-color: #252b3c;
|
||||
/** top-bar 组件 */
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
|
||||
export const MsgSuccess = (message: string) => {
|
||||
ElMessage.success({
|
||||
message: message,
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgInfo = (message: string) => {
|
||||
ElMessage.info({
|
||||
message: message,
|
||||
type: 'info',
|
||||
showClose: true,
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgWarning = (message: string) => {
|
||||
ElMessage.warning({
|
||||
message: message,
|
||||
type: 'warning',
|
||||
showClose: true,
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgError = (message: string) => {
|
||||
ElMessage.error({
|
||||
message: message,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
|
||||
export const MsgConfirm = (message: string, options = {}) => {
|
||||
const defaultOptions: Object = {
|
||||
type: 'warning',
|
||||
...options
|
||||
}
|
||||
return ElMessageBox.confirm(message, '确认', defaultOptions)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { store } from '@/stores'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { Role, Permission, ComplexPermission } from '@/common/permission/type'
|
||||
import { Role, Permission, ComplexPermission } from '@/utils/permission/type'
|
||||
/**
|
||||
* 是否包含当前权限
|
||||
* @param permission 当前权限
|
||||
|
|
@ -1,16 +1,19 @@
|
|||
<template >
|
||||
<div>
|
||||
<el-button v-hasPermission="'USER:DELETE'">用户删除权限</el-button>
|
||||
<el-button v-hasPermission="'USER:READ'">用户只读权限</el-button>
|
||||
<el-button v-hasPermission="new Role('USER')">普通用户角色</el-button>
|
||||
<el-button v-hasPermission="[new Role('ADMIN'), new Role('USER')]">普通用户或者管理员</el-button>
|
||||
<el-button
|
||||
v-hasPermission="{ permission: ['USER:READ', new Role('USER')], compare: 'AND' }">普通角色并且用户只读权限</el-button>
|
||||
<template>
|
||||
<div>
|
||||
<el-button v-hasPermission="'USER:DELETE'">用户删除权限</el-button>
|
||||
<el-button v-hasPermission="'USER:READ'">用户只读权限</el-button>
|
||||
<el-button v-hasPermission="new Role('USER')">普通用户角色</el-button>
|
||||
<el-button v-hasPermission="[new Role('ADMIN'), new Role('USER')]"
|
||||
>普通用户或者管理员</el-button
|
||||
>
|
||||
<el-button v-hasPermission="{ permission: ['USER:READ', new Role('USER')], compare: 'AND' }"
|
||||
>普通角色并且用户只读权限</el-button
|
||||
>
|
||||
|
||||
首页
|
||||
</div>
|
||||
首页
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Role } from "@/common/permission/type"
|
||||
import { Role } from '@/utils/permission/type'
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
placeholder="请输入邮箱"
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button :icon="UserFilled" />
|
||||
<el-button icon="UserFilled" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
placeholder="请输入验证码"
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button :icon="Key" />
|
||||
<el-button icon="Key" />
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button
|
||||
|
|
@ -61,12 +61,11 @@
|
|||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { UserFilled, Key } from '@element-plus/icons-vue'
|
||||
import type { CheckCodeRequest } from '@/api/user/type'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import UserApi from '@/api/user/index'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
|
||||
const router = useRouter()
|
||||
const CheckEmailForm = ref<CheckCodeRequest>({
|
||||
|
|
@ -108,7 +107,7 @@ const sendEmail = () => {
|
|||
resetPasswordFormRef.value?.validateField('email', (v: boolean) => {
|
||||
if (v) {
|
||||
UserApi.sendEmit(CheckEmailForm.value.email, 'reset_password', loading).then(() => {
|
||||
ElMessage.success('发送验证码成功')
|
||||
MsgSuccess('发送验证码成功')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ import type { RegisterRequest } from '@/api/user/type'
|
|||
import { UserFilled, Lock, Message, Key } from '@element-plus/icons-vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import UserApi from '@/api/user/index'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
const router = useRouter()
|
||||
|
|
@ -192,7 +192,7 @@ const sendEmail = () => {
|
|||
registerFormRef.value?.validateField('email', (v: boolean) => {
|
||||
if (v) {
|
||||
UserApi.sendEmit(registerForm.value.email, 'register', sendEmailLoading).then(() => {
|
||||
ElMessage.success('发送验证码成功')
|
||||
MsgSuccess('发送验证码成功')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
show-password
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button :icon="Lock" />
|
||||
<el-button icon="Lock" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
show-password
|
||||
>
|
||||
<template #prepend>
|
||||
<el-button :icon="Lock" />
|
||||
<el-button icon="Lock" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
|
@ -57,9 +57,8 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import type { ResetPasswordRequest } from '@/api/user/type'
|
||||
import { Lock } from '@element-plus/icons-vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import UserApi from '@/api/user/index'
|
||||
const router = useRouter()
|
||||
|
|
@ -127,7 +126,7 @@ const resetPassword = () => {
|
|||
?.validate()
|
||||
.then(() => UserApi.resetPassword(resetPasswordForm.value, loading))
|
||||
.then(() => {
|
||||
ElMessage.success('修改密码成功')
|
||||
MsgSuccess('修改密码成功')
|
||||
router.push({ name: 'login' })
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue