19-菜单管理添加弹窗显示

1<template> 2 <button @click="dialogFormVisable = true ">打开</button> 3 <el-dialog 4 v-model="dialogFormVisable" 5 :before-close="beforeClose" 6 title="添加权限" 7 width="500" 8 > 9 <el-form 10 ref="formRef" 11 label-width="100px" 12 label-position="left" 13 :model="form" 14 > 15 <el-form-item label="名称" prop="name"> 16 <el-input v-model="form.name" placeholder="请填写权限名称"/> 17 </el-form-item> 18 <el-form-item label="权限" prop="permissions"> 19 <el-tree 20 ref="treeRef" 21 style="max-width: 600px;" 22 :data="permissionData" 23 node-key="id" 24 show-checkbox 25 :default-checked-keys="defaultKeys" 26 /> 27 </el-form-item> 28 </el-form> 29 </el-dialog> 30</template> 31<script setup> 32 import { ref , reactive , onMounted } from 'vue' 33 import { userGetMenu } from '../../../api' 34 35 onMounted(() => { 36 //菜单数据 37 userGetMenu().then(({ data })=>{ 38 console.log(data) 39 permissionData.value = data.data 40 }) 41 }) 42 //form的数据 43 const form = reactive({ 44 name:'', 45 permissions:'' 46 }) 47 //树形菜单权限数据 48 const permissionData = ref([]) 49 //弹窗的显示隐藏 50 const dialogFormVisable = ref(false) 51 //关闭弹窗的回调 52 const beforeClose = () => { 53 dialogFormVisable.value = false 54 } 55 //选中权限 56 const defaultKeys = [4,5] 57 const treeRef = ref() 58</script> 59<style lang="less" scoped> 60</style>

1import request from '../utils/request' 2//发送验证码 3export const getCode = (data) => { 4 return request.post('/get/code',data) 5} 6 7//注册用户 8export const userAuthentication = (data) =>{ 9 return request.post('/user/authentication',data) 10} 11 12//登录 13export const login = (data) =>{ 14 return request.post('/login',data) 15} 16 17//权限管理列表 18export const authAdmin = (params) => { 19 return request.get('/auth/admin', { params }) 20} 21 22//菜单权限数据 23export const userGetMenu = (params) => { 24 return request.get('/user/getmenu', { params }) 25}
新添加的部分:

20-菜单管理添加接口联调
1<template> 2 <button @click="dialogFormVisable = true ">打开</button> 3 <el-dialog 4 v-model="dialogFormVisable" 5 :before-close="beforeClose" 6 title="添加权限" 7 width="500" 8 > 9 <el-form 10 ref="formRef" 11 label-width="100px" 12 label-position="left" 13 :model="form" 14 :rules="rules" 15 > 16 <el-form-item v-show="false" prop="id"> 17 <el-input v-model="form.id"/> 18 </el-form-item> 19 <el-form-item label="名称" prop="name"> 20 <el-input v-model="form.name" placeholder="请填写权限名称"/> 21 </el-form-item> 22 <el-form-item label="权限" prop="permissions"> 23 <el-tree 24 ref="treeRef" 25 style="max-width: 600px;" 26 :data="permissionData" 27 node-key="id" 28 show-checkbox 29 :default-checked-keys="defaultKeys" 30 :default-expanded-keys="[2]" 31 /> 32 </el-form-item> 33 </el-form> 34 <template #footer> 35 <div class="dialog-footer"> 36 <el-button type="primary" @click="confirm(formRef)">确认</el-button> 37 </div> 38 </template> 39 </el-dialog> 40</template> 41<script setup> 42 import { ref, reactive, onMounted } from 'vue' 43 import { userGetMenu, userSetMenu, menuList} from '../../../api' 44 45 46 onMounted(() => { 47 //菜单数据 48 userGetMenu().then(({ data })=>{ 49 console.log(data) 50 permissionData.value = data.data 51 }) 52 getListData() 53 }) 54 const paginationData = reactive({ 55 pageNum: 1, 56 pageSize: 10, 57 }) 58 59 //请求列表数据 60 const getListData = () =>{ 61 menuList(paginationData).then(( data ) => { 62 63 }) 64 } 65 66 const formRef = ref() 67 68 //form的数据 69 const form = reactive({ 70 id:'', 71 name:'', 72 permissions:'' 73 }) 74 //树形菜单权限数据 75 const permissionData = ref([]) 76 //弹窗的显示隐藏 77 const dialogFormVisable = ref(false) 78 //关闭弹窗的回调 79 const beforeClose = () => { 80 dialogFormVisable.value = false 81 } 82 //选中权限 83 const defaultKeys = [4,5] 84 const treeRef = ref() 85 86 const rules = reactive({ 87 name:[{ required: true, trigger:'blur',message:'请输入权限名称' }] 88 }) 89 //表单提交 90 const confirm = async(formEl) => { 91 if (!formEl) return 92 await formEl.validate((valid,fields) => { 93 if(valid){ 94 //获取到选择的checkbox数据 95 const permissions = JSON.stringify( treeRef.value.getCheckedKeys()) 96 userSetMenu({ name: form.name, permissions, id: form.id}).then(({ data }) => { 97 console.log(data) 98 }) 99 }else{ 100 console.log('error submit!' , fields ) 101 } 102 }) 103 } 104</script> 105<style lang="less" scoped> 106</style>

1import request from '../utils/request' 2//发送验证码 3export const getCode = (data) => { 4 return request.post('/get/code',data) 5} 6 7//注册用户 8export const userAuthentication = (data) =>{ 9 return request.post('/user/authentication',data) 10} 11 12//登录 13export const login = (data) =>{ 14 return request.post('/login',data) 15} 16 17//权限管理列表 18export const authAdmin = (params) => { 19 return request.get('/auth/admin', { params }) 20} 21 22//菜单权限数据 23export const userGetMenu = (params) => { 24 return request.get('/user/getmenu', { params }) 25} 26 27//菜单权限修改 28export const userSetMenu = (data) => { 29 return request.post('/user/setmenu',data) 30} 31 32//菜单权限列表 33export const menuList = (params) => { 34 return request.get('/menu/list', { params }) 35}

21-菜单管理列表和编辑逻辑

1<template> 2 <button @click="open(null)">打开 </button> 3 <el-table :data="tableData.list" style="width: 100%"> 4 <el-table-column prop="id" label="id" /> 5 <el-table-column prop="name" label="昵称" /> 6 <el-table-column prop="permissionName" label="菜单权限" width="500px"/> 7 <el-table-column label="操作"> 8 <template #default="scope"> 9 <el-button type="primary" @click="open(scope.row)">编辑</el-button> 10 </template> 11 </el-table-column> 12 </el-table> 13 <el-dialog 14 v-model="dialogFormVisable" 15 :before-close="beforeClose" 16 title="添加权限" 17 width="500" 18 > 19 <el-form 20 ref="formRef" 21 label-width="100px" 22 label-position="left" 23 :model="form" 24 :rules="rules" 25 > 26 <el-form-item v-show="false" prop="id"> 27 <el-input v-model="form.id"/> 28 </el-form-item> 29 <el-form-item label="名称" prop="name"> 30 <el-input v-model="form.name" placeholder="请填写权限名称"/> 31 </el-form-item> 32 <el-form-item label="权限" prop="permissions"> 33 <el-tree 34 ref="treeRef" 35 style="max-width: 600px;" 36 :data="permissionData" 37 node-key="id" 38 show-checkbox 39 :default-checked-keys="defaultKeys" 40 :default-expanded-keys="[2]" 41 /> 42 </el-form-item> 43 </el-form> 44 <template #footer> 45 <div class="dialog-footer"> 46 <el-button type="primary" @click="confirm(formRef)">确认</el-button> 47 </div> 48 </template> 49 </el-dialog> 50</template> 51<script setup> 52 import { ref, reactive, onMounted, nextTick } from 'vue' 53 import { userGetMenu, userSetMenu, menuList} from '../../../api' 54 55 56 onMounted(() => { 57 //菜单数据 58 userGetMenu().then(({ data })=>{ 59 console.log(data) 60 permissionData.value = data.data 61 }) 62 getListData() 63 }) 64 65 //列表数据 66 const tableData = reactive({ 67 list: [], 68 total: 0 69 }) 70 //打开弹窗 71 const open = (rowData = {}) =>{ 72 dialogFormVisable.value = true 73 // 弹窗打开form生成是异步的 74 nextTick(() => { 75 if(rowData){ 76 Object.assign(form, { id:rowData.id , name: rowData.name }) 77 treeRef.value.setCheckedKeys(rowData.permission) 78 } 79 }) 80 } 81 82 const paginationData = reactive({ 83 pageNum: 1, 84 pageSize: 10, 85 }) 86 87 //请求列表数据 88 const getListData = () =>{ 89 menuList(paginationData).then(({ data }) => { 90 const { list, total } = data.data 91 tableData.list = list 92 tableData.total = total 93 }) 94 } 95 96 const formRef = ref() 97 98 //form的数据 99 const form = reactive({ 100 id:'', 101 name:'', 102 permissions:'' 103 }) 104 //树形菜单权限数据 105 const permissionData = ref([]) 106 //弹窗的显示隐藏 107 const dialogFormVisable = ref(false) 108 //关闭弹窗的回调 109 const beforeClose = () => { 110 dialogFormVisable.value = false 111 //重置表单 112 formRef.value.resetFields() 113 //tree选择重置 114 treeRef.value.setCheckedKeys(defaultKeys) 115 } 116 //选中权限 117 const defaultKeys = [4,5] 118 const treeRef = ref() 119 120 const rules = reactive({ 121 name:[{ required: true, trigger:'blur',message:'请输入权限名称' }] 122 }) 123 //表单提交 124 const confirm = async(formEl) => { 125 if (!formEl) return 126 await formEl.validate((valid,fields) => { 127 if(valid){ 128 //获取到选择的checkbox数据 129 const permissions = JSON.stringify( treeRef.value.getCheckedKeys()) 130 userSetMenu({ name: form.name, permissions, id: form.id}).then(({ data }) => { 131 console.log(data) 132 }) 133 }else{ 134 console.log('error submit!' , fields ) 135 } 136 }) 137 } 138</script> 139<style lang="less" scoped> 140</style>
22-菜单管理剩余问题处理

1<template> 2 <panel-head/> 3 <div class="btns"> 4 <el-button :icon="Plus" type="primary" @click="open(null)" size="small">新增</el-button> 5 </div> 6 <el-table :data="tableData.list" style="width: 100%"> 7 <el-table-column prop="id" label="id" /> 8 <el-table-column prop="name" label="昵称" /> 9 <el-table-column prop="permissionName" label="菜单权限" width="500px"/> 10 <el-table-column label="操作"> 11 <template #default="scope"> 12 <el-button type="primary" @click="open(scope.row)">编辑</el-button> 13 </template> 14 </el-table-column> 15 </el-table> 16 <div class="pagination-info"> 17 <el-pagination 18 v-model:current-page="paginationData.pageNum" 19 :page-size="paginationData.pageSize" 20 :background="false" 21 size="small" 22 layout="total, prev, pager, next" 23 :total="tableData.total" 24 @size-change="handleSizeChange" 25 @current-change="handleCurrentChange" 26 /> 27 </div> 28 <el-dialog 29 v-model="dialogFormVisable" 30 :before-close="beforeClose" 31 title="添加权限" 32 width="500" 33 > 34 <el-form 35 ref="formRef" 36 label-width="100px" 37 label-position="left" 38 :model="form" 39 :rules="rules" 40 > 41 <el-form-item v-show="false" prop="id"> 42 <el-input v-model="form.id"/> 43 </el-form-item> 44 <el-form-item label="名称" prop="name"> 45 <el-input v-model="form.name" placeholder="请填写权限名称"/> 46 </el-form-item> 47 <el-form-item label="权限" prop="permissions"> 48 <el-tree 49 ref="treeRef" 50 style="max-width: 600px;" 51 :data="permissionData" 52 node-key="id" 53 show-checkbox 54 :default-checked-keys="defaultKeys" 55 :default-expanded-keys="[2]" 56 /> 57 </el-form-item> 58 </el-form> 59 <template #footer> 60 <div class="dialog-footer"> 61 <el-button type="primary" @click="confirm(formRef)">确认</el-button> 62 </div> 63 </template> 64 </el-dialog> 65</template> 66<script setup> 67 import { ref, reactive, onMounted, nextTick } from 'vue' 68 import { userGetMenu, userSetMenu, menuList} from '../../../api' 69 import { Plus } from '@element-plus/icons-vue' 70 71 72 onMounted(() => { 73 //菜单数据 74 userGetMenu().then(({ data })=>{ 75 console.log(data) 76 permissionData.value = data.data 77 }) 78 getListData() 79 }) 80 81 //列表数据 82 const tableData = reactive({ 83 list: [], 84 total: 0 85 }) 86 //打开弹窗 87 const open = (rowData = {}) =>{ 88 dialogFormVisable.value = true 89 // 弹窗打开form生成是异步的 90 nextTick(() => { 91 if(rowData){ 92 Object.assign(form, { id:rowData.id , name: rowData.name }) 93 treeRef.value.setCheckedKeys(rowData.permission) 94 } 95 }) 96 } 97 98 const paginationData = reactive({ 99 pageNum: 1, 100 pageSize: 10, 101 }) 102 103 const handleSizeChange = (val) => { 104 paginationData.pageSize = val 105 getListData() 106 } 107 const handleCurrentChange = (val) => { 108 paginationData.pageNum = val 109 getListData() 110 } 111 //请求列表数据 112 const getListData = () =>{ 113 menuList(paginationData).then(({ data }) => { 114 const { list, total } = data.data 115 tableData.list = list 116 tableData.total = total 117 }) 118 } 119 120 const formRef = ref() 121 122 //form的数据 123 const form = reactive({ 124 id:'', 125 name:'', 126 permissions:'' 127 }) 128 //树形菜单权限数据 129 const permissionData = ref([]) 130 //弹窗的显示隐藏 131 const dialogFormVisable = ref(false) 132 //关闭弹窗的回调 133 const beforeClose = () => { 134 dialogFormVisable.value = false 135 //重置表单 136 formRef.value.resetFields() 137 //tree选择重置 138 treeRef.value.setCheckedKeys(defaultKeys) 139 } 140 //选中权限 141 const defaultKeys = [4,5] 142 const treeRef = ref() 143 144 const rules = reactive({ 145 name:[{ required: true, trigger:'blur',message:'请输入权限名称' }] 146 }) 147 //表单提交 148 const confirm = async(formEl) => { 149 if (!formEl) return 150 await formEl.validate((valid,fields) => { 151 if(valid){ 152 //获取到选择的checkbox数据 153 const permissions = JSON.stringify( treeRef.value.getCheckedKeys()) 154 userSetMenu({ name: form.name, permissions, id: form.id}).then(({ data }) => { 155 beforeClose() 156 getListData() 157 }) 158 }else{ 159 console.log('error submit!' , fields ) 160 } 161 }) 162 } 163</script> 164<style lang="less" scoped> 165.btns{ 166 padding: 10px 0 10px 10px ; 167 background-color: #fff; 168} 169</style>


1<template> 2 <div class="panel-heading"> 3 <div class="panel-lead"> 4 <div class="title">菜单管理</div> 5 <p class="description">菜单规则通常对应一个控制器的方法,同时菜单栏数据也从规则中获取</p> 6 </div> 7 </div> 8</template> 9 10<script setup> 11</script> 12 13<style lang="less" scoped> 14.panel-heading { 15 padding: 15px; 16 background: #e8edf0; 17 border-color: #e8edf0; 18 position: relative; 19 .panel-lead { 20 font-size: 14px; 21 .title { 22 font-weight: bold; 23 font-style: normal; 24 } 25 .description { 26 margin-top: 5px; 27 } 28 } 29 } 30</style>


1import { createApp } from 'vue' 2import './style.css' 3import App from './App.vue' 4import router from './router' 5import store from './store' 6import PanelHead from './components/panelHead.vue' 7 8 9router.beforeEach((to,from) =>{ 10 const token = localStorage.getItem('pz_token') 11 //非登录页面token不存在 12 if (!token && to.path !== '/login') { 13 return '/login' 14 }else if (token && to.path === '/login'){ 15 return '/' 16 }else{ 17 return true 18 } 19}) 20 21// 如果您正在使用CDN引入,请删除下面一行。 22import * as ElementPlusIconsVue from '@element-plus/icons-vue' 23 24const app = createApp(App) 25for (const [key, component] of Object.entries(ElementPlusIconsVue)) { 26 app.component(key, component) 27} 28 29app.component('PanelHead',PanelHead) 30//路由挂载 31app.use(router) 32//store挂载 33app.use(store) 34app.mount('#app') 35
23-账号管理列表




24-账号管理编辑分页功能完成

1<template> 2 <panel-head/> 3 <el-table :data="tableData.list" style="width: 100%"> 4 <el-table-column prop="id" label="id" /> 5 <el-table-column prop="name" label="昵称" /> 6 <el-table-column prop="permissions_id" label="所属组别" > 7 <template #default="scope"> 8 {{ permissionName(scope.row.permissions_id) }} 9 </template> 10 </el-table-column> 11 <el-table-column prop="mobile" label="手机号" /> 12 13 <el-table-column prop="active" label="状态" > 14 <template #default="scope"> 15 <el-tag :type="scope.row.active ? 'success' : 'danger' ">{{ scope.row.active ? '正常' : '失效'}}</el-tag> 16 </template> 17 </el-table-column> 18 19 <el-table-column label="创建时间" > 20 <template #default="scope"> 21 <div class="flex-box"> 22 <el-icon><Clock /></el-icon> 23 <span style="margin-left : 10px">{{ scope.row.create_time}}</span> 24 </div> 25 </template> 26 </el-table-column> 27 28 <el-table-column label="操作"> 29 <template #default="scope"> 30 <el-button type="primary" @click="open(scope.row)">编辑</el-button> 31 </template> 32 </el-table-column> 33 </el-table> 34 35 <div class="pagination-info"> 36 <el-pagination 37 v-model:current-page="paginationData.pageNum" 38 :page-size="paginationData.pageSize" 39 :background="false" 40 size="small" 41 layout="total, prev, pager, next" 42 :total="tableData.total" 43 @size-change="handleSizeChange" 44 @current-change="handleCurrentChange" 45 /> 46 </div> 47 <el-dialog 48 v-model="dialogFormVisable" 49 :before-close="beforeClose" 50 title="添加权限" 51 width="500" 52 > 53 <el-form 54 ref="formRef" 55 label-width="100px" 56 label-position="left" 57 :model="form" 58 :rules="rules" 59 > 60 <el-form-item label="手机号" prop="mobile"> 61 <el-input v-model="form.mobile" disabled/> 62 </el-form-item> 63 <el-form-item label="昵称" prop="name"> 64 <el-input v-model="form.name" /> 65 </el-form-item> 66 <el-form-item label="菜单权限" prop="permissions_id"> 67 <el-select 68 v-model="form.permissions_id" 69 placeholder="请选择菜单权限" 70 style="width: 240px" 71 > 72 <el-option 73 v-for="item in options" 74 :key="item.id" 75 :label="item.name" 76 :value="item.id" 77 /> 78 </el-select> 79 </el-form-item> 80 </el-form> 81 <template #footer> 82 <div class="dialog-footer"> 83 <el-button type="primary" @click="confirm(formRef)">确认</el-button> 84 </div> 85 </template> 86 </el-dialog> 87</template> 88 89<script setup> 90import { authAdmin, menuSelectList, updateUser } from'../../../api' 91import { ref, reactive, onMounted } from 'vue' 92import dayjs from 'dayjs' 93 94const paginationData = reactive({ 95 pageNum: 1, 96 pageSize: 10, 97}) 98 99//列表数据 100const tableData = reactive({ 101 list: [], 102 total: 0 103}) 104 105onMounted(() => { 106 getListData() 107 menuSelectList().then(({ data }) => { 108 options.value = data.data 109 }) 110}) 111//请求列表 112const getListData = () => { 113 authAdmin(paginationData).then(({data}) => { 114 console.log(data, 'authAdmin') 115 const { list, total } = data.data 116 list.forEach(item => { 117 item.create_time = dayjs(item.create_time).format('YYYY-MM-DD') 118 }) 119 tableData.list = list 120 tableData.total = total 121 }) 122} 123 124const handleSizeChange = (val) => { 125 paginationData.pageSize = val 126 getListData() 127} 128const handleCurrentChange = (val) => { 129 paginationData.pageNum = val 130 getListData() 131} 132 133//弹窗 134const dialogFormVisable = ref(false) 135const beforeClose = () => { 136 137} 138 139const rules = reactive({ 140 name:[{ required: true, trigger: 'blur' , message:'请填写昵称' }], 141 permissions_id:[{ required: true, trigger: 'blur' , message:'请选择菜单权限' }], 142 143}) 144 145//编辑表单 146const formRef = ref() 147const form = reactive({ 148 name:'', 149 permissions_id:'', 150 151}) 152//表单提交 153const confirm = async (formEl) => { 154 if (!formEl) return 155 await formEl.validate((valid,fields) => { 156 if(valid){ 157 const { name, permissions_id } = form 158 updateUser({ name, permissions_id}).then(({ data }) => { 159 if( data.code === 10000 ){ 160 dialogFormVisable.value = false 161 getListData() 162 } 163 }) 164 }else{ 165 console.log('error submit!' , fields ) 166 } 167 }) 168} 169 170const options = ref([]) 171//根据权限id匹配权限名称 172const permissionName = (id) => { 173 const data = options.value.find(el => el.id === id) 174 return data ? data.name : '超级管理员' 175} 176const open = ( rowData ) => { 177 dialogFormVisable.value = true 178 Object.assign(form, { mobile:rowData.mobile, name: rowData.name, permissions_id:rowData.permissions_id }) 179} 180</script> 181 182<style lang="less" scoped> 183.flex-box{ 184 display: flex; 185 align-items: center; 186} 187</style>


1import request from '../utils/request' 2//发送验证码 3export const getCode = (data) => { 4 return request.post('/get/code',data) 5} 6 7//注册用户 8export const userAuthentication = (data) =>{ 9 return request.post('/user/authentication',data) 10} 11 12//登录 13export const login = (data) =>{ 14 return request.post('/login',data) 15} 16 17//权限管理列表 18export const authAdmin = (params) => { 19 return request.get('/auth/admin', { params }) 20} 21 22//菜单权限数据 23export const userGetMenu = () => { 24 return request.get('/user/getmenu') 25} 26 27//菜单权限修改 28export const userSetMenu = (data) => { 29 return request.post('/user/setmenu',data) 30} 31 32//菜单权限列表 33export const menuList = (params) => { 34 return request.get('/menu/list', { params }) 35} 36 37//权限下拉列表 38export const menuSelectList = () =>{ 39 return request.get('/menu/selectlist',) 40} 41 42//用户数据修改 43export const updateUser = (data) => { 44 return request.post('/update/user',data) 45} 46
25-用户权限接口联调和动态路由数据组装



1<template> 2 <div class="header-container"> 3 <div class="header-left flex-box" > 4 <el-icon class="icon" size="20" @click="store.commit('collapseMenu')"><Fold /></el-icon> 5 <ul class="flex-box"> 6 <li 7 v-for="(item,index) in selectMenu" 8 :key="item.path" 9 :class="{selected: route.path === item.path}" 10 class="tab flex-box"> 11 <el-icon size="12" ><component :is="item.icon" /></el-icon> 12 <router-link class="text flex-box" :to="{ path:item.path }"> 13 {{item.name}} 14 </router-link> 15 <el-icon size="12" class="close" @click="closeTab(item,index)"><Close /></el-icon> 16 </li> 17 </ul> 18 </div> 19 <div class="header-right"> 20 <el-dropdown @command="handleClick"> 21 <div class="el-dropdown-link flex-box"> 22 <el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"/> 23 <p class="user-name">admin</p> 24 </div> 25 <template #dropdown> 26 <el-dropdown-item command="cancel">退出</el-dropdown-item> 27 </template> 28 </el-dropdown> 29 </div> 30 </div> 31</template> 32 33<script setup> 34import { useStore } from 'vuex' 35import { computed } from 'vue' 36import { useRoute,useRouter } from 'vue-router' 37//拿到store的实例 38const store = useStore() 39// 当前路由对象 40const route = useRoute() 41const router = useRouter() 42const selectMenu = computed( ()=> store.state.menu.selectMenu) 43//点击关闭tag 44const closeTab = (item,index) =>{ 45 store.commit('closeMenu',item) 46 //删除的非当前页tag 47 if(route.path !== item.path){ 48 return 49 } 50 const selectMenuDate = selectMenu.value 51 //删除的最后一项 52 if( index === selectMenuData.length){ 53 //如果tag只有一个元素 54 if(!selectMenuData.length) { 55 router.push('/') 56 }else{ 57 router.push({ 58 path:selectMenuData[index -1].path 59 }) 60 } 61 }else(//如果删除的是中间位置tag 62 router.push({ 63 path:selectMenuData[index].path 64 }) 65 ) 66} 67 68const handleClick = (command) => { 69 if(command === "cancel" ){ 70 localStorage.removeItem('pz_token') 71 localStorage.removeItem('pz_userInfo') 72 73 window.location.href = window.location.origin 74 } 75} 76</script> 77 78<style lang="less" scoped> 79.flex-box{ 80 display: flex; 81 align-items: center; 82 height: 100%; 83} 84.header-container { 85 display: flex; 86 justify-content: space-between; 87 align-items: center; 88 height: 100%; 89 background-color: #fff; 90 padding-right: 25px; 91 .header-left{ 92 height: 100%; 93 .icon{ 94 width: 45px; 95 height: 100%; 96 } 97 .icon:hover{ 98 background-color: #f5f5f5; 99 cursor: pointer; 100 } 101 .tab{ 102 padding: 0 10px; 103 height: 100%; 104 .text{ 105 margin: 0 5px; 106 } 107 .close{ 108 visibility: hidden; 109 } 110 &.selected{ 111 a{ 112 color: #409eff; 113 } 114 i{ 115 color: #409eff; 116 } 117 background-color: #f5f5f5; 118 } 119 } 120 .tab:hover{ 121 background-color: #f5f5f5; 122 .close{ 123 visibility: inherit; 124 cursor: pointer; 125 color: #000; 126 } 127 } 128 } 129 .header-right{ 130 .user-name{ 131 margin-left: 10px; 132 } 133 } 134 a{ 135 height: 100%; 136 color: #333; 137 font-size: 15px; 138 } 139} 140</style>




1<template> 2 <el-row class="login-container" justify="center" :align="'middle'"> 3 <el-card style="max-width: 480px"> 4 <template #header> 5 <div class="card-header"> 6 <img :src="imgUrl" alt=""> 7 </div> 8 </template> 9 <div class="jump-link"> 10 <el-link type="primary" @click="handleChange">{{ formType ? '返回登录' : '注册账号' }}</el-link> 11 </div> 12 <el-form 13 ref="loginFromRef" 14 :model="loginForm" 15 style="max-width: 600px" 16 class="demo-ruleForm" 17 :rules="rules" 18 > 19 <el-form-item prop="userName"> 20 <el-input v-model="loginForm.userName" :prefix-icon="UserFilled" placeholder="手机号"></el-input> 21 </el-form-item> 22 <el-form-item prop="passWord"> 23 <el-input v-model="loginForm.passWord" type="password" :prefix-icon="Lock" placeholder="密码"></el-input> 24 </el-form-item> 25 <el-form-item v-if="formType" prop="validCode"> 26 <el-input v-model="loginForm.validCode" :prefix-icon="Lock" placeholder="验证码"> 27 <template #append> 28 <span @click="countdownChange">{{ countdown.validText }}</span> 29 </template> 30 </el-input> 31 </el-form-item> 32 <el-form-item> 33 <el-button type="primary" :style="{width:'100%'}" @click="submitForm(loginFromRef)"> 34 {{ formType ? '注册账号' : '登录'}} 35 </el-button> 36 </el-form-item> 37 </el-form> 38 </el-card> 39 </el-row> 40</template> 41 42<script setup> 43import { ref, reactive, computed } from 'vue' 44import { getCode, userAuthentication, login, menuPermissions } from '../../api' 45import { UserFilled, Lock } from '@element-plus/icons-vue' 46import { useRouter } from 'vue-router' 47import { useStore } from 'vuex' 48 49const imgUrl = new URL('../../../public/login-head.png', import.meta.url).href 50 51//表单数据 52const loginForm = reactive({ 53 userName: '', 54 passWord: '', 55 validCode: '', 56}) 57//切换表单(0登录 1注册) 58const formType = ref(0) 59//点击切换登录和注册 60const handleChange = () => { 61 formType.value = formType.value ? 0 : 1 62} 63//账号校验规则 64const validateUser = (rule,value,callback) =>{ 65 //不能为空 66 if(value === ''){ 67 callback(new Error('请输入账号')) 68 }else{ 69 const phoneReg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/ 70 phoneReg.test(value) ? callback() : callback(Error('手机号格式不对,请输入正确手机号')) 71 } 72} 73//密码校验 74const validatePass = (rule,value,callback) =>{ 75 //不能为空 76 if(value === ''){ 77 calllback(new Error('请输入密码')) 78 }else{ 79 const reg = /^[a-zA-Z0-9_-]{4,16}$/ 80 reg.test(value) ? callback() : callback(Error('密码格式不对,需要4-16位字符,请确认格式')) 81 } 82} 83//表单校验 84const rules = reactive({ 85 userName : [{ validator: validateUser, trigger:'blur'}], 86 passWord : [{ validator: validatePass, trigger:'blur'}] 87}) 88//发送短信 89const countdown = reactive({ 90 validText:'获取验证码', 91 time:60 92}) 93let flag = false 94const countdownChange = () =>{ 95 //如果已发送不处理 96 if(flag) return 97 //判断手机号是否正确 98 const phoneReg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/ 99 if (!loginForm.userName || !phoneReg.test(loginForm.userName)){ 100 return ElMessage({ 101 message: '请检查手机号是否正确', 102 type: 'warning', 103 }) 104 } 105 //倒计时 106 const time = setInterval(()=>{ 107 if( countdown.time <= 0){ 108 countdown.time = 60 109 countdown.validText = `获取验证码` 110 flag = false 111 clearInterval(time) 112 }else{ 113 countdown.time -= 1 114 countdown.validText = [`剩余${countdown.time}s`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.time.md) 115 } 116 },1000) 117 flag = true 118 getCode({ tel: loginForm.userName}).then(({ data }) => { 119 if(data.code === 10000){ 120 ElMessage.success('发送成功') 121 } 122 }) 123} 124 125const router = useRouter() 126const loginFromRef = ref() 127const store = useStore() 128 129const routerList = computed(() => store.state.menu.routerList) 130//表单提交 131const submitForm = async (formEl) => { 132 if (!formEl) return 133 //手动触发校验 134 await formEl.validate((valid, fields) => { 135 if (valid) { 136 //注册页面 137 if(formType.value){ 138 userAuthentication(loginForm).then(({ data }) => { 139 if (data.code === 10000) { 140 ElMessage.success('注册成功,请登录') 141 formType.value = 0 142 } 143 }) 144 }else{ 145 //登录页面 146 login(loginForm).then(({data}) => { 147 if (data.code === 10000) { 148 ElMessage.success('登录成功!') 149 console.log(data) 150 //将token和用户信息缓存到浏览器 151 localStorage.setItem('pz_token', data.data.token) 152 localStorage.setItem('pz_userInfo', JSON.stringify(data.data.userInfo)) 153 menuPermissions().then(({ data }) => { 154 store.commit('dynamicMenu', data.data) 155 console.log(routerList, 'routerList') 156 // router.push('/') 157 }) 158 159 } 160 }) 161 } 162 } else { 163 console.log('error submit!', fields) 164 } 165 }) 166} 167</script> 168 169<style lang="less" scoped> 170:deep(.el-card__header) { 171 padding: 0 172} 173 .login-container { 174 height: 100%; 175 .card-header{ 176 background-color: #899fe1; 177 img { 178 width: 430px; 179 } 180 } 181 .jump-link { 182 text-align: right; 183 margin-bottom: 10px; 184 } 185 } 186</style>


1const state = { 2 isCollapse : false, 3 selectMenu: [], 4 routerList: [] 5} 6const mutations = { 7 collapseMenu(state){ 8 state.isCollapse = !state.isCollapse 9 }, 10 addMenu(state,payload) { 11 //对数据进行去重 12 if(state.selectMenu.findIndex(item => item.path === payload.path) === -1){ 13 state.selectMenu.push(payload) 14 15 } 16 }, 17 closeMenu(state,payload){ 18 //找到点击数据的索引 19 const index = state.selectMenu.findIndex(val => val.name === payload.name ) 20 //通过索引删除数组指定元素 21 state.selectMenu.splice(index,1) 22 }, 23 dynamicMenu( state, payload ) { 24 //通过glob导入文件 25 const modules = import.meta.glob('../views/**/**/*.vue') 26 console.log(modules) 27 function routerSet(router){ 28 router.forEach(route => { 29 //判断没有子菜单,拼接路由数据 30 if ( !route.children ){ 31 const url = [`../views${route.meta.path}/index.vue`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.meta.md) 32 //拿到获取的vue组件 33 route.component = modules[url] 34 }else{ 35 routerSet(route.children) 36 } 37 }) 38 } 39 routerSet(payload) 40 //拿到完整的路由数据 41 state.routerList = payload 42 } 43 44} 45 46export default{ 47 state, 48 mutations 49}
26-动态路由添加和vuex持久化实现






























