Browse Source

fix: 恢复:权限不重新到页面

zhangrenyuan/feature-20250714163943-金币前端二期
lihui 3 weeks ago
parent
commit
d41c8a793f
  1. 10
      src/main.ts
  2. 45
      src/store/index.js
  3. 55
      src/utils/menuUtils.js
  4. 238
      src/views/home.vue
  5. 53
      src/views/login.vue
  6. 16
      src/views/usergold/clientCount.vue

10
src/main.ts

@ -12,13 +12,13 @@ import VxeUI from 'vxe-pc-ui'
import 'vxe-pc-ui/lib/style.css'
import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css'
const a = createApp(App)
import { useAdminStore } from '../src/store'
// 全局注册 ElementPlus 图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
a.component(key, component)
}
const pinia = createPinia()
// 使用 ElementPlus 和路由器
a.use(ElementPlus, {
@ -27,8 +27,12 @@ a.use(ElementPlus, {
.use(router)
.use(VxeUI)
.use(VxeUITable)
.use(createPinia())
.use(pinia)
.mount('#app')
// 恢复localStorage数据
const adminStore = useAdminStore()
adminStore.initFromLocalStorage()
// 注册 JsonExcel 组件
a.component('downloadExcel', JsonExcel)

45
src/store/index.js

@ -0,0 +1,45 @@
// src/store/index.js
import { defineStore } from 'pinia'
export const useAdminStore = defineStore('admin', {
state: () => ({
adminData: null, // 用户信息
menuTree: null, // 菜单权限树
}),
actions: {
// 设置用户信息并同步到localStorage
setAdminData(info) {
this.adminData = info
localStorage.setItem('adminData', JSON.stringify(info))
},
// 设置菜单树并同步到localStorage
setMenuTree(tree) {
this.menuTree = tree
localStorage.setItem('menuTree', JSON.stringify(tree))
},
// 从localStorage初始化数据
initFromLocalStorage() {
const adminData = localStorage.getItem('adminData')
const menuTree = localStorage.getItem('menuTree')
if (adminData) {
this.adminData = JSON.parse(adminData)
}
if (menuTree) {
this.menuTree = JSON.parse(menuTree)
}
},
// 清空状态并移除localStorage数据
clearState() {
this.adminData = null
this.menuTree = null
localStorage.removeItem('adminData')
localStorage.removeItem('menuTree')
// localStorage.removeItem('token')
}
}
})

55
src/utils/menu-utils.ts → src/utils/menuUtils.js

@ -1,4 +1,4 @@
// 菜单树过滤
// 菜单树过滤 (展示的? )
export function filterMenu(menuList) {
return menuList
// 过滤不是4级的 123 为菜单
@ -36,6 +36,9 @@ export const getRoutePath = (menu) => {
'审核页面': '/audit',
'财务审核': '/audit',
'充值审核': '/audit/rechargeAudit',
'退款审核': '/audit/refundAudit',
'汇率管理': '/rate',
'消耗管理': '/coinConsume',
@ -44,6 +47,7 @@ export const getRoutePath = (menu) => {
'权限管理': '/permissions',
'充值管理': '/coinRecharge',
'充值页面': '/coinRecharge',
'退款管理': '/coinRefund',
@ -55,51 +59,4 @@ export const getRoutePath = (menu) => {
// 未匹配的菜单默认使用id作为路由(可根据实际需求调整)
return routeMap[menu.menuName] || '/noPermissionPage'
}
// 这是获取用户信息的接口
const adminData = ref({
name: ''
})
import API from "@/util/http.js";
import {ref} from "vue";
export const getAdminData = async function () {
try {
const result = await API({url: '/admin/userinfo', data: {}})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
return result
} catch (error) {
console.log('请求失败', error)
}
}
// 权限检查函数
export const hasPermission = (to, menuList) => {
if (!menuList || menuList.length === 0) return false;
// 转换路由路径为菜单名称
const routePath = to.path;
const menuName = Object.keys(getRoutePath).find(key => getRoutePath[key] === routePath);
if (!menuName) return false;
// 扁平化菜单树以便查找
const flattenMenu = (menus) => {
return menus.reduce((acc, menu) => {
acc.push(menu);
if (menu.children) {
acc = acc.concat(flattenMenu(menu.children));
}
return acc;
}, []);
};
const flatMenuList = flattenMenu(menuList);
return flatMenuList.some(menu => menu.menuName === menuName);
};
}

238
src/views/home.vue

@ -1,118 +1,37 @@
<script setup>
//
import {onMounted, ref} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import {ref} from 'vue'
import {useRouter} from 'vue-router'
import {ElMessage} from 'element-plus'
import API from '@/util/http'
import dmmn from '../assets/link.png'
import moment from 'moment'
import ChangePassword from '@/components/changePassword.vue'
//
const route = useRoute()
import {useAdminStore} from '@/store'
import {storeToRefs} from 'pinia'
import {filterMenu, getRoutePath} from "@/utils/menuUtils.js";
//
const menuList = ref([])
//
const adminStore = useAdminStore()
// adminData menuTree
const {adminData, menuTree} = storeToRefs(adminStore)
// ,menuTree
menuList.value = filterMenu(menuTree.value)
/**
* 调用 /menu/tree 接口获取菜单数据
*/
const fetchMenuTree = async function() {
try {
const result = await API({ url: '/menu/tree', data: {id: adminData.value.roleId} })
return result.data //
} catch (error) {
console.error('菜单数据请求失败:', error)
return { code: 500, msg: '获取菜单失败' }
}
}
function filterMenu(menuList) {
return menuList
.filter(menu => menu.menuType !== 4)
.map(menu => ({
...menu,
children: menu.children ? filterMenu(menu.children) : []
}))
.sort((a, b) => a.priority - b.priority); // id
}
/**
* 映射菜单名称到路由路径
*/
const getRoutePath = (menu) => {
// keymenuNamevalue
const routeMap = {
'工作台': '/workspace',
'审核页面': '/audit',
'财务审核': '/audit',
'充值审核': '/rechargeAudit',
'退款审核': '/refundAudit',
'汇率管理': '/rate',
'消耗管理': '/coinConsume',
'消耗页面': '/coinConsume',
'权限管理': '/permissions',
'充值管理': '/coinRecharge',
'充值页面': '/coinRecharge',
'退款管理': '/coinRefund',
'退款页面': '/coinRefund',
'客户账户明细': '/usergold',
};
// 使id
return routeMap[menu.menuName] || '/workspace'
}
console.log("menuList", menuList.value)
const router = useRouter()
const imgrule1 = dmmn
const messageVisible = ref(false)
//
const adminData = ref({
name: ''
})
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const areas = ref([])
const currentArea = ref('全部')
const getAreas = async function () {
try {
const result = await API({ url: '/general/adminMarkets', data: {
account: adminData.value.account,
} })
areas.value = result.data
console.log('请求成功', result)
} catch (error) {
console.log('请求失败', error)
}
}
//
const openMessage = function () {
messageVisible.value = true
}
//
const closeMessage = function () {
messageVisible.value = false
}
@ -120,93 +39,23 @@ const message = function () {
openMessage()
}
//
const exportList = ref([])
//
const exportListLoading = ref(false)
//
const getTagType = (state) => {
switch (state) {
case 0:
return 'info';
case 1:
return 'primary';
case 2:
return'success';
case 3:
return 'danger';
default:
return 'info';
}
}
//
const getTagText = (state) => {
switch (state) {
case 0:
return '待执行';
case 1:
return '执行中';
case 2:
return'执行完成';
case 3:
return '执行出错';
default:
return '未知状态';
}
}
//
const showPasswordDialog = ref(false)
//
const downloadExportFile = (item) => {
if (item.state === 2) {
const link = document.createElement('a')
link.href = item.url
link.download = item.fileName
link.click()
} else {
ElMessage.warning('文件还在导出中,请稍后再试')
}
//
const openChangePassword = () => {
showPasswordDialog.value = true
}
function logout() {
const machineId = localStorage.getItem('machineId')
localStorage.removeItem('token')
adminStore.clearState()
router.push('/login?machineId=' + machineId)
ElMessage.success('退出成功')
}
//
onMounted(async function () {
//
await getAdminData()
const menus = await fetchMenuTree()
menuList.value = filterMenu(menus)
})
//
const changeDataByArea = (item) => {
currentArea.value = item
}
//
const exportListVisible = ref(false)
//
const showPasswordDialog = ref(false)
//
const openExportList = () => {
getExportList()
exportListVisible.value = true
}
//
const openChangePassword = () => {
showPasswordDialog.value = true
}
//
const changePasswordRef = ref(null)
const handleClosePasswordDialog = () => {
changePasswordRef.value?.resetFields()
}
</script>
@ -224,31 +73,44 @@ const handleClosePasswordDialog = () => {
z-index: 100; /* 确保侧边栏在其他元素之上 */
">
<div class="logo">
<img src="../assets/新logo.png" alt="logo" style="width: 80px; height: 80px" />
<img src="../assets/新logo.png" alt="logo" style="width: 80px; height: 80px"/>
<!-- <div style="font-size: 16px; font-weight: bold; color: black; text-align: center;" ><h1>海外金币管理系统</h1></div> -->
</div>
<el-card style="min-height: 90%;">
<el-menu :router="true" class="el-menu-vertical-demo" :default-active="$route.path">
<el-menu
:router="true"
class="el-menu-vertical-demo"
:default-active="$route.path"
>
<!-- 递归渲染菜单层级 -->
<template v-for="menu in menuList" :key="menu.id">
<!-- 有子菜单的父级菜单menuType=2 且存在children -->
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.id.toString()">
<el-sub-menu
v-if="menu.children && menu.children.length > 0"
:index="menu.id.toString()"
>
<template #title>
<el-icon>
<Folder />
<Folder/>
</el-icon>
<span>{{ menu.menuName }}</span>
</template>
<!-- 子菜单 -->
<template v-for="child in menu.children" :key="child.id">
<!-- 子菜单为叶子节点无children -->
<el-menu-item v-if="!child.children || child.children.length === 0" :index="getRoutePath(child)">
<el-menu-item
v-if="!child.children || child.children.length === 0"
:index="getRoutePath(child)"
>
<span>{{ child.menuName }}</span>
</el-menu-item>
<!-- 子菜单有下级 -->
<el-sub-menu v-else :index="child.id.toString()">
<el-sub-menu
v-else
:index="child.id.toString()"
>
<template #title>
<span>{{ child.menuName }}</span>
</template>
@ -263,9 +125,12 @@ const handleClosePasswordDialog = () => {
</el-sub-menu>
<!-- 无子菜单的一级菜单 -->
<el-menu-item v-else :index="getRoutePath(menu)">
<el-menu-item
v-else
:index="getRoutePath(menu)"
>
<el-icon>
<Folder />
<Folder/>
</el-icon>
<span>{{ menu.menuName }}</span>
</el-menu-item>
@ -290,7 +155,7 @@ const handleClosePasswordDialog = () => {
<el-sub-menu index="1" class="admin">
<template #title>
<el-image :src="imgrule1" alt="错误" style="width: 50px; height: 50px" />
<el-image :src="imgrule1" alt="错误" style="width: 50px; height: 50px"/>
<span style="margin-left: 10px">{{ adminData.name }}</span>
</template>
<el-menu-item @click="message()">查看个人信息</el-menu-item>
@ -331,11 +196,16 @@ const handleClosePasswordDialog = () => {
</template>
</el-dialog>
<!-- 自定义密码修改弹窗组件 父組件和子組件通信-->
<el-dialog v-model="showPasswordDialog" :center="true" width="470px" @close="handleClosePasswordDialog">
<ChangePassword ref="changePasswordRef" @confirm="showPasswordDialog = false" />
<!-- 自定义密码修改弹窗组件 -->
<el-dialog
v-model="showPasswordDialog"
:center="true"
width="470px"
>
<ChangePassword @confirm="showPasswordDialog = false"/>
</el-dialog>
</div>
</template>

53
src/views/login.vue

@ -1,11 +1,12 @@
<script setup>
import {ref, onMounted, reactive, computed} from 'vue'
import {onMounted, ref} from 'vue'
import {ElMessage} from 'element-plus'
import axios from 'axios'
import request from '@/util/http'
import {useRouter} from 'vue-router'
import {VscGlobe} from 'vue-icons-plus/vsc'
import API from "@/util/http.js";
import {useAdminStore} from '@/store'
//
import {filterMenu, findFirstAccessibleMenu, getRoutePath} from "../utils/menuUtils.js"
const router = useRouter() //
//
@ -27,40 +28,47 @@ function getMachineId() {
}
}
const adminRoleId = ref(null)
const form = ref({account: null, password: '', token: '', machineId: machineId1.value})
const adminRoleId = ref(null)
//
const login = async function () {
try {
const result = await request({
url: '/admin/login',
data: form.value
})
console.log('看看传给后端的参数', form.value)
if (result.code == 200) {
console.log('传给后端的参数', form.value)
if (result.code === 200) {
// token
localStorage.setItem('token', result.msg)
// localStorage.setItem('permission', result.data.permission)
adminRoleId.value = result.data.roleId
await getMenuTree()
// pinia
const adminStore = useAdminStore()
//
adminStore.setAdminData(result.data)
// 使 adminRoleId
adminRoleId.value = result.data.roleId
//
//
const menuTree = await getMenuTree()
const filteredMenu = filterMenu(menuTree)
//
const firstMenu = findFirstAccessibleMenu(filteredMenu)
console.log('第一个有效菜单项:', firstMenu)
console.log('存储菜单树menuTree', menuTree)
adminStore.setMenuTree(menuTree)
//
//
const filteredMenu = filterMenu(adminStore.menuTree)
// 访
const firstMenu = findFirstAccessibleMenu(filteredMenu)
// 访 path
const redirectPath = firstMenu ? getRoutePath(firstMenu) : '/noPermissionPage'
console.log('获取到的菜单树:', filteredMenu)
console.log('跳转路径:', redirectPath)
//
router.push(redirectPath)
// router.push('/workspace')
ElMessage.success('登录成功')
console.log('请求成功', result)
} else {
@ -71,11 +79,8 @@ console.log('获取到的菜单树:', filteredMenu)
} catch (error) {
console.log('请求失败', error)
ElMessage.error('登录失败,请检查账号密码')
}
}
//
const getMenuTree = async function () {
//
@ -89,10 +94,6 @@ const getMenuTree = async function () {
}
}
//
import {filterMenu,findFirstAccessibleMenu,getRoutePath} from "../utils/menu-utils.js"
onMounted(() => {
getMachineId()

16
src/views/usergold/clientCount.vue

@ -2,16 +2,16 @@
<div>
<!-- 这里放置标签切换的按钮 -->
<el-button-group>
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button
:type="activeTab === 'detail' ? 'primary' : 'default'"
@click="goToDetail"
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button
:type="activeTab === 'detail' ? 'primary' : 'default'"
@click="goToDetail"
>
金币明细
</el-button>
<el-button
:type="activeTab === 'balance' ? 'primary' : 'default'"
@click="goToBalance"
<el-button
:type="activeTab === 'balance' ? 'primary' : 'default'"
@click="goToBalance"
>
金币余额
</el-button>
@ -52,7 +52,7 @@ watch(() => route.name, (newName) => {
activeTab.value = 'detail';
} else if (newName === 'clientCountBalance') {
activeTab.value = 'balance';
}});
}});
//
// if (route.name === 'usergold') {

Loading…
Cancel
Save