193 lines
6.9 KiB
Vue
193 lines
6.9 KiB
Vue
<template>
|
|
<el-container class="layout">
|
|
<el-header class="layout-header">
|
|
<div class="main-title">博客管理后台</div>
|
|
<div class="nav-btns-right">
|
|
<el-dropdown @command="dropdownMenuCommand">
|
|
<el-button link type="primary">
|
|
<UserFilled style="width: 18px" />
|
|
{{ realname }}
|
|
<ArrowDown style="width: 18px"/>
|
|
</el-button>
|
|
<template #dropdown>
|
|
<el-dropdown-menu>
|
|
<el-dropdown-item command="home">返回首页</el-dropdown-item>
|
|
<el-dropdown-item command="changePassword">修改密码</el-dropdown-item>
|
|
<el-dropdown-item command="logout" divided>退出</el-dropdown-item>
|
|
</el-dropdown-menu>
|
|
</template>
|
|
</el-dropdown>
|
|
</div>
|
|
</el-header>
|
|
<el-container>
|
|
<el-aside width="200px">
|
|
<el-menu :default-active="defaultActiveMenuKey" :default-openeds="openMenuNames" style="height: 100%;">
|
|
<el-sub-menu v-for="menu in menus" :key="menu.name" :index="menu.name">
|
|
<template #title>
|
|
<component :is="menu.icon" style="width: 18px; margin-right: 5px;"></component>
|
|
<span>{{menu.title}}</span>
|
|
</template>
|
|
<el-menu-item v-for="(subItem,subIndex) in menu.child" :key="subIndex" :index="subItem.path" @click="openMenu(subItem.path)">
|
|
{{subItem.title}}
|
|
</el-menu-item>
|
|
</el-sub-menu>
|
|
</el-menu>
|
|
</el-aside>
|
|
<el-main class="layout-main">
|
|
<div class="layout-tabs">
|
|
<el-tabs type="card" class="nav-tabs" v-model="store.state.activeTab" @tab-change="openMenu" @tab-remove="removeTab">
|
|
<el-tab-pane label="首页" name="/"></el-tab-pane>
|
|
<el-tab-pane v-for="tab in store.state.tabs" :key="tab.name" :label="tab.title" :name="tab.path" closable></el-tab-pane>
|
|
</el-tabs>
|
|
</div>
|
|
<div class="layout-content" v-if="mainViewReady">
|
|
<router-view class="main-view" v-slot="{ Component }">
|
|
<keep-alive :include="keepViews">
|
|
<component :is="Component" />
|
|
</keep-alive>
|
|
</router-view>
|
|
</div>
|
|
<div class="layout-copy">2016-{{currentYear}} © colorfulsweet 上次更新:{{ version }}</div>
|
|
</el-main>
|
|
</el-container>
|
|
</el-container>
|
|
|
|
<el-dialog v-model="changePwdModal" title="修改密码" width="420px" @closed="resetPwdForm">
|
|
<el-form ref="changePwdForm" :model="changePwdData" :rules="changePwdRules" :label-width="100">
|
|
<el-form-item label="旧密码" prop="oldPassword">
|
|
<el-input v-model="changePwdData.oldPassword" type="password" show-password />
|
|
</el-form-item>
|
|
<el-form-item label="新密码" prop="newPassword">
|
|
<el-input v-model="changePwdData.newPassword" type="password" show-password />
|
|
</el-form-item>
|
|
<el-form-item label="确认密码" prop="confirmPassword">
|
|
<el-input v-model="changePwdData.confirmPassword" type="password" show-password />
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="changePwdModal = false">取消</el-button>
|
|
<el-button type="primary" @click="submitChangePassword" :loading="changePwdLoading">确定</el-button>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, reactive, computed, nextTick } from 'vue'
|
|
import { useStore } from 'vuex'
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
import menus from '../config/menu'
|
|
import http from '@/utils/http'
|
|
import { ElMessage } from 'element-plus'
|
|
import { VForm } from '@/types'
|
|
|
|
const store = useStore()
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
|
|
const version = process.env.VERSION
|
|
const currentYear = new Date().getFullYear()
|
|
const defaultActiveMenuKey = ref<string | null>(null)
|
|
const openMenuNames = ref<string[]>([])
|
|
const mainViewReady = ref(false)
|
|
|
|
const changePwdModal = ref(false)
|
|
const changePwdLoading = ref(false)
|
|
const changePwdForm = ref<VForm>()
|
|
const changePwdData = reactive({
|
|
oldPassword: '',
|
|
newPassword: '',
|
|
confirmPassword: ''
|
|
})
|
|
const changePwdRules = {
|
|
oldPassword: [
|
|
{ required: true, message: '请输入旧密码', trigger: 'blur' }
|
|
],
|
|
newPassword: [
|
|
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
|
{ min: 8, max: 16, message: '密码长度8~16位', trigger: 'blur' },
|
|
{ pattern: /^(?![\d]+$)(?![a-zA-Z]+$)(?![-=+_.,]+$)[\da-zA-Z-=+_.,]{8,16}$/, message: '密码由字母、数字、特殊字符中的任意两种组成', trigger: 'blur' }
|
|
],
|
|
confirmPassword: [
|
|
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
|
|
{ validator: (_rule: object, value: string, callback: Function) => {
|
|
value !== changePwdData.newPassword ? callback(new Error('两次输入的密码不一致')) : callback()
|
|
}, trigger: 'blur'
|
|
}
|
|
]
|
|
}
|
|
|
|
const realname = computed((): null | string => {
|
|
return store.state.loginInfo.userInfo
|
|
? store.state.loginInfo.userInfo.realname : null
|
|
})
|
|
const keepViews = computed((): string[] => {
|
|
return store.state.tabs
|
|
.filter((item: any) => item.name)
|
|
.map((item: any) => item.name)
|
|
})
|
|
|
|
// created
|
|
defaultActiveMenuKey.value = route.path
|
|
if (defaultActiveMenuKey.value) {
|
|
let result = /^\/(.*)\//.exec(defaultActiveMenuKey.value)
|
|
if (result) {
|
|
openMenuNames.value.push(result[1])
|
|
}
|
|
}
|
|
if (!store.state.loginInfo.token) {
|
|
router.push('/login')
|
|
} else {
|
|
http.post<{token: string}, any>('/api/v2/common/verifyToken', {token: store.state.loginInfo.token}).then(data => {
|
|
store.commit('login', {userInfo: data.userInfo})
|
|
mainViewReady.value = true
|
|
}).catch(() => {
|
|
router.push('/login')
|
|
})
|
|
}
|
|
|
|
function dropdownMenuCommand(command: string): void {
|
|
switch (command) {
|
|
case 'home':
|
|
router.push('/')
|
|
break
|
|
case 'changePassword':
|
|
changePwdModal.value = true
|
|
break
|
|
case 'logout':
|
|
http.post('/api/v2/common/logout').finally(() => {
|
|
store.commit('logout')
|
|
router.push('/login')
|
|
})
|
|
break
|
|
}
|
|
}
|
|
function submitChangePassword(): void {
|
|
changePwdForm.value?.validate(async (valid: boolean) => {
|
|
if (!valid) return
|
|
changePwdLoading.value = true
|
|
await http.post('/api/v2/system/user/changePassword', changePwdData).finally(() => {
|
|
changePwdLoading.value = false
|
|
})
|
|
changePwdModal.value = false
|
|
ElMessage.success('密码修改成功')
|
|
})
|
|
}
|
|
function resetPwdForm(): void {
|
|
changePwdData.oldPassword = ''
|
|
changePwdData.newPassword = ''
|
|
changePwdData.confirmPassword = ''
|
|
nextTick(() => changePwdForm.value?.clearValidate())
|
|
}
|
|
function openMenu(path: string): void {
|
|
router.push(path)
|
|
}
|
|
function removeTab(path: string): void {
|
|
store.commit('removeTab', path)
|
|
if (store.state.activeTab === path) {
|
|
const { tabs } = store.state
|
|
openMenu(tabs[tabs.length - 1]?.path || '/')
|
|
}
|
|
}
|
|
</script> |