Browse Source

fix: 多次调用tree ,权限不重新到页面

zhangrenyuan/feature-20250714163943-金币前端二期
lihui 3 weeks ago
parent
commit
aaf4be815a
  1. 10
      src/main.ts
  2. 62
      src/router/index.js
  3. 45
      src/store/index.js
  4. 61
      src/utils/menuUtils.js
  5. 121
      src/views/audit/audit.vue
  6. 114
      src/views/consume/coinConsume.vue
  7. 230
      src/views/home.vue
  8. 53
      src/views/login.vue
  9. 112
      src/views/recharge/coinRecharge.vue
  10. 112
      src/views/refund/coinRefund.vue
  11. 99
      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 'vxe-pc-ui/lib/style.css'
import VxeUITable from 'vxe-table' import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css' import 'vxe-table/lib/style.css'
const a = createApp(App) const a = createApp(App)
import { useAdminStore } from '../src/store'
// 全局注册 ElementPlus 图标 // 全局注册 ElementPlus 图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
a.component(key, component) a.component(key, component)
} }
const pinia = createPinia()
// 使用 ElementPlus 和路由器 // 使用 ElementPlus 和路由器
a.use(ElementPlus, { a.use(ElementPlus, {
@ -27,8 +27,12 @@ a.use(ElementPlus, {
.use(router) .use(router)
.use(VxeUI) .use(VxeUI)
.use(VxeUITable) .use(VxeUITable)
.use(createPinia())
.use(pinia)
.mount('#app') .mount('#app')
// 恢复localStorage数据
const adminStore = useAdminStore()
adminStore.initFromLocalStorage()
// 注册 JsonExcel 组件 // 注册 JsonExcel 组件
a.component('downloadExcel', JsonExcel) a.component('downloadExcel', JsonExcel)

62
src/router/index.js

@ -1,17 +1,11 @@
import {createRouter, createWebHashHistory} from 'vue-router'; import {createRouter, createWebHashHistory} from 'vue-router';
import axios from "axios"; import axios from "axios";
import request from "@/util/http.js";
import {ref} from "vue";
import {storeToRefs} from "pinia";
import {useAdminStore} from "@/store/index.js";
// 路由定义(包含权限映射 meta.permissionId) // 路由定义(包含权限映射 meta.permissionId)
const routes = [ const routes = [
// {
// path: '/workspace',
// name: "workspace",
// component: () => import("../views/workspace/audit.vue"),
// meta: { permissionId: 10 } // 对应"工作台展示"id=10
// },
{ {
path: '/', path: '/',
redirect: "/login" redirect: "/login"
@ -43,7 +37,7 @@ const routes = [
meta: {permissionId: 40}, meta: {permissionId: 40},
// redirect: '/index', // redirect: '/index',
children: [ children: [
// 充值审核========================================
// 充值审核
{ {
path: 'rechargeAudit', path: 'rechargeAudit',
name: "rechargeAudit", name: "rechargeAudit",
@ -61,7 +55,6 @@ const routes = [
}, },
// 金币消耗 // 金币消耗
{ {
path: '/coinConsume', path: '/coinConsume',
@ -229,26 +222,14 @@ const getAllPermissionIds = (menuTree) => {
return permissionIds; return permissionIds;
}; };
// 存储管理员信息(全局可访问)
const adminData = ref(null);
// 获取管理员信息(返回Promise,方便路由守卫中使用)
export const getAdminData = async function () {
try {
const result = await request({
url: "/admin/userinfo",
});
adminData.value = result; // 存储管理员信息(包含roleId)
return result; // 返回结果,供路由守卫使用
} catch (error) {
console.log("获取管理员信息失败", error);
throw error; // 抛出错误,让路由守卫捕获
}
};
// 全局路由守卫 // 全局路由守卫
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const adminStore = useAdminStore()
const { adminData, menuTree } = storeToRefs(adminStore)
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
const machineId = localStorage.getItem("machineId"); const machineId = localStorage.getItem("machineId");
@ -265,41 +246,28 @@ router.beforeEach(async (to, from, next) => {
let roleId = null; let roleId = null;
console.log('adminData:', adminData) console.log('adminData:', adminData)
try { try {
await getAdminData(); // 等待管理员信息获取完成
roleId = adminData.value.roleId; roleId = adminData.value.roleId;
if (!roleId) { if (!roleId) {
throw new Error("未获取到roleId");
localStorage.removeItem('token'); // 清除token,强制重新登录
next(`/login?machineId=${machineId || ''}`);
return;
} }
} catch (error) { } catch (error) {
localStorage.removeItem('token'); // 清除token,强制重新登录 localStorage.removeItem('token'); // 清除token,强制重新登录
adminStore.clearState()
next(`/login?machineId=${machineId || ''}`); next(`/login?machineId=${machineId || ''}`);
return; return;
} }
let userPermissionIds = []; let userPermissionIds = [];
try {
const response = await request( {url: "/menu/tree",
data:{id: roleId}
});
console.log('roleId:', roleId)
console.log('response:', response)
console.log('userPermissionIds:', userPermissionIds)
if (response.code === 200 && response.data) {
userPermissionIds = getAllPermissionIds(response.data); // 提取权限id
console.log('userPermissionIds:', userPermissionIds)
}
} catch (error) {
console.error('获取菜单树失败:', error);
localStorage.removeItem('token');
next(`/login?machineId=${machineId || ''}`);
return;
}
// 拿权限id
userPermissionIds = getAllPermissionIds(menuTree.value)
// 2.4 权限验证(逻辑不变) // 2.4 权限验证(逻辑不变)
console.log('to.meta:', to.meta) console.log('to.meta:', to.meta)
const requiresPermission = to.meta && to.meta.permissionId; const requiresPermission = to.meta && to.meta.permissionId;
if (requiresPermission) { if (requiresPermission) {
const hasPermission = Array.isArray(requiresPermission) const hasPermission = Array.isArray(requiresPermission)

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')
}
}
})

61
src/utils/menuUtils.js

@ -0,0 +1,61 @@
// 菜单树过滤 (展示的? )
export function filterMenu(menuList) {
return menuList
// 过滤不是4级的 123 为菜单
.filter(menu => menu.menuType !== 4)
.map(menu => ({
...menu,
children: menu.children ? filterMenu(menu.children) : []
}))
.sort((a, b) => a.priority - b.priority); // 按 id 升序
}
// 辅助函数:查找第一个可访问的菜单项
export function findFirstAccessibleMenu(menuList) {
if (!menuList || menuList.length === 0) return null
for (const menu of menuList) {
if (menu.menuType === 1) { // 根
const childResult = findFirstAccessibleMenu(menu.children)
if (childResult) return childResult
} else if (menu.menuType === 2) { // 目录
return menu
} else if (menu.menuType === 3) { // 菜单
return menu
}
}
return null
}
// 路由映射
export const getRoutePath = (menu) => {
// 路由映射表:key为接口menuName,value为对应路由路径
const routeMap = {
'工作台': '/workspace',
'审核页面': '/audit',
'财务审核': '/audit',
'充值审核': '/audit/rechargeAudit',
'退款审核': '/audit/refundAudit',
'汇率管理': '/rate',
'消耗管理': '/coinConsume',
'消耗页面': '/coinConsume',
'权限管理': '/permissions',
'充值管理': '/coinRecharge',
'充值页面': '/coinRecharge',
'退款管理': '/coinRefund',
'退款页面': '/coinRefund',
'客户账户明细': '/usergold',
};
// 未匹配的菜单默认使用id作为路由(可根据实际需求调整)
return routeMap[menu.menuName] || '/noPermissionPage'
}

121
src/views/audit/audit.vue

@ -1,66 +1,117 @@
<template> <template>
<div> <div>
<!-- 这里放置标签切换的按钮 -->
<el-button-group> <el-button-group>
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button <el-button
:type="activeTab === 'rechargeAudit' ? 'primary' : 'default'" :type="activeTab === 'rechargeAudit' ? 'primary' : 'default'"
@click="goRechargeAudit"
@click="navigateTo('rechargeAudit')"
:disabled="!hasRechargePermission"
> >
充值审核 充值审核
</el-button> </el-button>
<el-button <el-button
:type="activeTab === 'refundAudit' ? 'primary' : 'default'" :type="activeTab === 'refundAudit' ? 'primary' : 'default'"
@click="goRefundAudit"
@click="navigateTo('refundAudit')"
:disabled="!hasRefundPermission"
> >
退款审核 退款审核
</el-button> </el-button>
</el-button-group> </el-button-group>
<!-- 渲染子路由组件 -->
<router-view></router-view> <router-view></router-view>
</div> </div>
</template> </template>
<script setup> <script setup>
import {onMounted, ref, watch} from 'vue';
import {ref, watch, onMounted, computed} from 'vue';
import {useRouter, useRoute} from 'vue-router'; import {useRouter, useRoute} from 'vue-router';
import {storeToRefs} from 'pinia';
import {useAdminStore} from '@/store/index.js';
const router = useRouter();//
const route = useRoute();//
// activeTab
const activeTab = ref(route.name === 'rechargeAudit' ? 'rechargeAudit' : 'refundAudit');
//clientCountBalancebalancedetail
//clientCountDetaildetail
const router = useRouter();
const route = useRoute();
const adminStore = useAdminStore();
const {menuTree} = storeToRefs(adminStore);
const activeTab = ref('');
const goRechargeAudit = () => {
// activeTab detail
activeTab.value = 'rechargeAudit';
router.push({ name: 'rechargeAudit' });
};
//
const hasRechargePermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '充值审核' || menu.menuName === '财务审核'
);
});
const goRefundAudit = () => {
// activeTab balance
activeTab.value = 'refundAudit';
router.push({ name: 'refundAudit' });
};
// 退
const hasRefundPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '退款审核' || menu.menuName === '财务审核'
);
});
// activeTab
watch(() => route.name, (newName) => {
if (newName === 'rechargeAudit') {
activeTab.value = 'rechargeAudit';
} else if (newName === 'refundAudit') {
activeTab.value = 'refundAudit';
}});
//
const navigateTo = (name) => {
//
if ((name === 'rechargeAudit' && !hasRechargePermission.value) ||
(name === 'refundAudit' && !hasRefundPermission.value)) {
return;
}
activeTab.value = name;
router.push({name});
};
//
// if (route.name === 'usergold') {
// router.push({ name: 'clientCountDetail' });
// }
//
const getDefaultAuditRoute = () => {
//
if (hasRechargePermission.value) return 'rechargeAudit';
// 退
if (hasRefundPermission.value) return 'refundAudit';
// null
return null;
};
//
watch(() => route.path, (newPath) => {
// /audit
if (newPath === '/audit') {
const defaultRoute = getDefaultAuditRoute();
if (defaultRoute) {
navigateTo(defaultRoute);
} else {
console.warn('用户没有充值审核和退款审核的权限');
// router.push({ name: 'noPermission' });
}
}
});
onMounted(async function () {
console.log("@@@@@@@@@@@@",route.name)
//
watch(() => route.name, (newName) => {
//
if (newName === 'rechargeAudit' && hasRechargePermission.value) {
activeTab.value = newName;
} else if (newName === 'refundAudit' && hasRefundPermission.value) {
activeTab.value = newName;
}
}); });
// -
onMounted(() => {
//
if (route.path === '/audit') {
const defaultRoute = getDefaultAuditRoute();
if (defaultRoute) {
navigateTo(defaultRoute);
} else {
// console.warn('退');
router.push({ name: 'noPermission' });
}
} else {
//
if (route.name === 'rechargeAudit' && hasRechargePermission.value) {
activeTab.value = route.name;
} else if (route.name === 'refundAudit' && hasRefundPermission.value) {
activeTab.value = route.name;
}
}
});
</script> </script>

114
src/views/consume/coinConsume.vue

@ -1,61 +1,121 @@
<template> <template>
<div> <div>
<!-- 这里放置标签切换的按钮 -->
<el-button-group> <el-button-group>
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button <el-button
:type="activeTab === 'add' ? 'primary' : 'default'" :type="activeTab === 'add' ? 'primary' : 'default'"
@click="goToAdd"
@click="navigateTo('add')"
:disabled="!hasAddPermission"
> >
新增消耗 新增消耗
</el-button> </el-button>
<el-button <el-button
:type="activeTab === 'detail' ? 'primary' : 'default'" :type="activeTab === 'detail' ? 'primary' : 'default'"
@click="goToDetail"
@click="navigateTo('detail')"
:disabled="!hasDetailPermission"
> >
金币消耗明细 金币消耗明细
</el-button> </el-button>
</el-button-group> </el-button-group>
<!-- 渲染子路由组件 -->
<router-view></router-view> <router-view></router-view>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue';
import {ref, watch, onMounted, computed} from 'vue'; // computed
import {useRouter, useRoute} from 'vue-router'; import {useRouter, useRoute} from 'vue-router';
import {storeToRefs} from 'pinia';
import {useAdminStore} from '@/store/index.js';
const router = useRouter();//
const route = useRoute();//
// activeTab
const activeTab = ref(route.name === 'coinConsumeDetail' ? 'detail' : 'add');
//coinConsumeDetaildetailadd
//coinConsumeadd
const router = useRouter();
const route = useRoute();
const adminStore = useAdminStore();
const {menuTree} = storeToRefs(adminStore);
const activeTab = ref('');
const goToAdd = () => {
// activeTab add
activeTab.value = 'add';
router.push({ name: 'addCoinConsume' });
//
const routeMap = {
add: 'addCoinConsume',
detail: 'coinConsumeDetail'
}; };
const goToDetail = () => {
// activeTab detail
activeTab.value = 'detail';
router.push({ name: 'coinConsumeDetail' });
// computed
const hasAddPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '新增消耗' || menu.menuName === '消耗管理'
);
});
//
const hasDetailPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '金币消耗明细' || menu.menuName === '消耗管理'
);
});
//
const navigateTo = (tab) => {
//
if ((tab === 'add' && !hasAddPermission.value) ||
(tab === 'detail' && !hasDetailPermission.value)) {
return;
}
activeTab.value = tab;
router.push({name: routeMap[tab]});
}; };
// activeTab
//
const getDefaultConsumeRoute = () => {
//
if (hasAddPermission.value) return 'add';
//
if (hasDetailPermission.value) return 'detail';
// null
return null;
};
//
watch(() => route.name, (newName) => { watch(() => route.name, (newName) => {
if (newName === 'addCoinConsume') {
if (newName === routeMap.add && hasAddPermission.value) {
activeTab.value = 'add'; activeTab.value = 'add';
} else if (newName === 'coinConsumeDetail') {
} else if (newName === routeMap.detail && hasDetailPermission.value) {
activeTab.value = 'detail'; activeTab.value = 'detail';
} }
}); });
//
// if (route.name === 'coinConsume') {
// router.push({ name: 'addCoinConsume' });
// }
// 访
watch(() => route.path, (newPath) => {
if (newPath === '/coinConsume') { // /coinConsume
const defaultRoute = getDefaultConsumeRoute();
if (defaultRoute) {
navigateTo(defaultRoute);
} else {
console.warn('用户没有新增消耗和金币消耗明细的权限');
// router.push({ name: 'noPermission' }); //
}
}
});
//
onMounted(() => {
//
if (route.path === '/coinConsume') { // /coinConsume
const defaultRoute = getDefaultConsumeRoute();
if (defaultRoute) {
navigateTo(defaultRoute);
} else {
// console.warn('');
router.push({ name: 'noPermission' }); //
}
} else {
//
if (route.name === routeMap.add && hasAddPermission.value) {
activeTab.value = 'add';
} else if (route.name === routeMap.detail && hasDetailPermission.value) {
activeTab.value = 'detail';
}
}
});
</script> </script>

230
src/views/home.vue

@ -1,118 +1,37 @@
<script setup> <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 {ElMessage} from 'element-plus'
import API from '@/util/http'
import dmmn from '../assets/link.png' import dmmn from '../assets/link.png'
import moment from 'moment'
import ChangePassword from '@/components/changePassword.vue' 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 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 router = useRouter()
const imgrule1 = dmmn const imgrule1 = dmmn
const messageVisible = ref(false) 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 () { const openMessage = function () {
messageVisible.value = true messageVisible.value = true
} }
//
const closeMessage = function () { const closeMessage = function () {
messageVisible.value = false messageVisible.value = false
} }
@ -120,93 +39,23 @@ const message = function () {
openMessage() 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() { function logout() {
const machineId = localStorage.getItem('machineId') const machineId = localStorage.getItem('machineId')
localStorage.removeItem('token') localStorage.removeItem('token')
adminStore.clearState()
router.push('/login?machineId=' + machineId) router.push('/login?machineId=' + machineId)
ElMessage.success('退出成功') 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> </script>
@ -229,11 +78,18 @@ const handleClosePasswordDialog = () => {
</div> </div>
<el-card style="min-height: 90%;"> <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"> <template v-for="menu in menuList" :key="menu.id">
<!-- 有子菜单的父级菜单menuType=2 且存在children --> <!-- 有子菜单的父级菜单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> <template #title>
<el-icon> <el-icon>
<Folder/> <Folder/>
@ -243,12 +99,18 @@ const handleClosePasswordDialog = () => {
<!-- 子菜单 --> <!-- 子菜单 -->
<template v-for="child in menu.children" :key="child.id"> <template v-for="child in menu.children" :key="child.id">
<!-- 子菜单为叶子节点无children --> <!-- 子菜单为叶子节点无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> <span>{{ child.menuName }}</span>
</el-menu-item> </el-menu-item>
<!-- 子菜单有下级 --> <!-- 子菜单有下级 -->
<el-sub-menu v-else :index="child.id.toString()">
<el-sub-menu
v-else
:index="child.id.toString()"
>
<template #title> <template #title>
<span>{{ child.menuName }}</span> <span>{{ child.menuName }}</span>
</template> </template>
@ -263,7 +125,10 @@ const handleClosePasswordDialog = () => {
</el-sub-menu> </el-sub-menu>
<!-- 无子菜单的一级菜单 --> <!-- 无子菜单的一级菜单 -->
<el-menu-item v-else :index="getRoutePath(menu)">
<el-menu-item
v-else
:index="getRoutePath(menu)"
>
<el-icon> <el-icon>
<Folder/> <Folder/>
</el-icon> </el-icon>
@ -331,11 +196,16 @@ const handleClosePasswordDialog = () => {
</template> </template>
</el-dialog> </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> </el-dialog>
</div> </div>
</template> </template>

53
src/views/login.vue

@ -1,11 +1,12 @@
<script setup> <script setup>
import {ref, onMounted, reactive, computed} from 'vue'
import {onMounted, ref} from 'vue'
import {ElMessage} from 'element-plus' import {ElMessage} from 'element-plus'
import axios from 'axios'
import request from '@/util/http' import request from '@/util/http'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import {VscGlobe} from 'vue-icons-plus/vsc'
import API from "@/util/http.js"; import API from "@/util/http.js";
import {useAdminStore} from '@/store'
//
import {filterMenu, findFirstAccessibleMenu, getRoutePath} from "../utils/menuUtils.js"
const router = useRouter() // const router = useRouter() //
// //
@ -27,40 +28,47 @@ function getMachineId() {
} }
} }
const adminRoleId = ref(null)
const form = ref({account: null, password: '', token: '', machineId: machineId1.value}) const form = ref({account: null, password: '', token: '', machineId: machineId1.value})
const adminRoleId = ref(null)
// //
const login = async function () { const login = async function () {
try { try {
const result = await request({ const result = await request({
url: '/admin/login', url: '/admin/login',
data: form.value 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('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 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' const redirectPath = firstMenu ? getRoutePath(firstMenu) : '/noPermissionPage'
console.log('获取到的菜单树:', filteredMenu)
console.log('跳转路径:', redirectPath)
//
router.push(redirectPath) router.push(redirectPath)
// router.push('/workspace')
ElMessage.success('登录成功') ElMessage.success('登录成功')
console.log('请求成功', result) console.log('请求成功', result)
} else { } else {
@ -71,11 +79,8 @@ console.log('获取到的菜单树:', filteredMenu)
} catch (error) { } catch (error) {
console.log('请求失败', error) console.log('请求失败', error)
ElMessage.error('登录失败,请检查账号密码') ElMessage.error('登录失败,请检查账号密码')
} }
} }
// //
const getMenuTree = async function () { const getMenuTree = async function () {
// //
@ -89,10 +94,6 @@ const getMenuTree = async function () {
} }
} }
//
import {filterMenu,findFirstAccessibleMenu,getRoutePath} from "../utils/menu-utils.js"
onMounted(() => { onMounted(() => {
getMachineId() getMachineId()

112
src/views/recharge/coinRecharge.vue

@ -1,61 +1,119 @@
<template> <template>
<div> <div>
<!-- 这里放置标签切换的按钮 -->
<el-button-group> <el-button-group>
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button <el-button
:type="activeTab === 'add' ? 'primary' : 'default'" :type="activeTab === 'add' ? 'primary' : 'default'"
@click="goToAdd"
@click="navigateTo('add')"
:disabled="!hasAddPermission"
> >
新增充值 新增充值
</el-button> </el-button>
<el-button <el-button
:type="activeTab === 'detail' ? 'primary' : 'default'" :type="activeTab === 'detail' ? 'primary' : 'default'"
@click="goToDetail"
@click="navigateTo('detail')"
:disabled="!hasDetailPermission"
> >
金币充值明细 金币充值明细
</el-button> </el-button>
</el-button-group> </el-button-group>
<!-- 渲染子路由组件 -->
<router-view></router-view> <router-view></router-view>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue';
import {ref, watch, onMounted, computed} from 'vue';
import {useRouter, useRoute} from 'vue-router'; import {useRouter, useRoute} from 'vue-router';
import {storeToRefs} from 'pinia';
import {useAdminStore} from '@/store/index.js';
const router = useRouter();//
const route = useRoute();//
const activeTab = ref(route.name === 'coinRechargeDetail' ? 'detail' : 'add');
//coinRechargeDetaildetailadd
//coinRechargeadd
//coinRechargeadd
const router = useRouter();
const route = useRoute();
const adminStore = useAdminStore();
const {menuTree} = storeToRefs(adminStore);
//
const routeMap = {
add: 'addCoinRecharge',
detail: 'coinRechargeDetail'
};
const goToAdd = () => {
// activeTab add
activeTab.value = 'add';
router.push({ name: 'addCoinRecharge' });
//
const activeTab = ref('');
//
const hasAddPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '新增充值' || menu.menuName === '充值管理'
);
});
//
const hasDetailPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '金币充值明细' || menu.menuName === '充值管理'
);
});
//
const navigateTo = (tab) => {
//
if ((tab === 'add' && !hasAddPermission.value) ||
(tab === 'detail' && !hasDetailPermission.value)) {
return;
}
activeTab.value = tab;
router.push({name: routeMap[tab]});
}; };
const goToDetail = () => {
// activeTab detail
activeTab.value = 'detail';
router.push({ name: 'coinRechargeDetail' });
//
const getDefaultRoute = () => {
if (hasAddPermission.value) return 'add';
if (hasDetailPermission.value) return 'detail';
return null;
}; };
// activeTab
//
watch(() => route.name, (newName) => { watch(() => route.name, (newName) => {
if (newName === 'addCoinRecharge') {
if (newName === routeMap.add && hasAddPermission.value) {
activeTab.value = 'add'; activeTab.value = 'add';
} else if (newName === 'coinRechargeDetail') {
} else if (newName === routeMap.detail && hasDetailPermission.value) {
activeTab.value = 'detail'; activeTab.value = 'detail';
} }
}); });
//
// if (route.name === 'coinRecharge') {
// router.push({ name: 'addCoinRecharge' });
// }
// 访
watch(() => route.path, (newPath) => {
if (newPath === '/coinRecharge') { // /coinRecharge
const defaultTab = getDefaultRoute();
if (defaultTab) {
navigateTo(defaultTab);
} else {
console.warn('用户没有新增充值和金币充值明细的权限');
// router.push({ name: 'noPermission' }); //
}
}
});
//
onMounted(() => {
//
if (route.name === 'coinRecharge' || route.path === '/coinRecharge') {
const defaultTab = getDefaultRoute();
if (defaultTab) {
navigateTo(defaultTab);
} else {
// console.warn('');
router.push({ name: 'noPermission' }); //
}
} else {
//
if (route.name === routeMap.add && hasAddPermission.value) {
activeTab.value = 'add';
} else if (route.name === routeMap.detail && hasDetailPermission.value) {
activeTab.value = 'detail';
}
}
});
</script> </script>

112
src/views/refund/coinRefund.vue

@ -1,61 +1,119 @@
<template> <template>
<div> <div>
<!-- 这里放置标签切换的按钮 -->
<el-button-group> <el-button-group>
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button <el-button
:type="activeTab === 'add' ? 'primary' : 'default'" :type="activeTab === 'add' ? 'primary' : 'default'"
@click="goToAdd"
@click="navigateTo('add')"
:disabled="!hasAddPermission"
> >
新增退款 新增退款
</el-button> </el-button>
<el-button <el-button
:type="activeTab === 'detail' ? 'primary' : 'default'" :type="activeTab === 'detail' ? 'primary' : 'default'"
@click="goToDetail"
@click="navigateTo('detail')"
:disabled="!hasDetailPermission"
> >
金币退款明细 金币退款明细
</el-button> </el-button>
</el-button-group> </el-button-group>
<!-- 渲染子路由组件 -->
<router-view></router-view> <router-view></router-view>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue';
import {ref, watch, onMounted, computed} from 'vue';
import {useRouter, useRoute} from 'vue-router'; import {useRouter, useRoute} from 'vue-router';
import {storeToRefs} from 'pinia';
import {useAdminStore} from '@/store/index.js';
const router = useRouter();//
const route = useRoute();//
// activeTab
const activeTab = ref(route.name === 'coinRefundDetail' ? 'detail' : 'add');
//coinRefundDetaildetailadd
//coinRefundadd
const router = useRouter();
const route = useRoute();
const adminStore = useAdminStore();
const {menuTree} = storeToRefs(adminStore);
//
const routeMap = {
add: 'addCoinRefund',
detail: 'coinRefundDetail'
};
const goToAdd = () => {
// activeTab add
activeTab.value = 'add';
router.push({ name: 'addCoinRefund' });
//
const activeTab = ref('');
//
const hasAddPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '新增退款' || menu.menuName === '退款管理'
);
});
//
const hasDetailPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '金币退款明细' || menu.menuName === '退款管理'
);
});
//
const navigateTo = (tab) => {
//
if ((tab === 'add' && !hasAddPermission.value) ||
(tab === 'detail' && !hasDetailPermission.value)) {
return;
}
activeTab.value = tab;
router.push({name: routeMap[tab]});
}; };
const goToDetail = () => {
// activeTab detail
activeTab.value = 'detail';
router.push({ name: 'coinRefundDetail' });
//
const getDefaultRoute = () => {
if (hasAddPermission.value) return 'add';
if (hasDetailPermission.value) return 'detail';
return null;
}; };
// activeTab
//
watch(() => route.name, (newName) => { watch(() => route.name, (newName) => {
if (newName === 'addCoinRefund') {
if (newName === routeMap.add && hasAddPermission.value) {
activeTab.value = 'add'; activeTab.value = 'add';
} else if (newName === 'coinRefundDetail') {
} else if (newName === routeMap.detail && hasDetailPermission.value) {
activeTab.value = 'detail'; activeTab.value = 'detail';
} }
}); });
//
// if (route.name === 'coinRefund') {
// router.push({ name: 'addCoinRefund' });
// }
// 访
watch(() => route.path, (newPath) => {
if (newPath === '/coinRefund') {
const defaultTab = getDefaultRoute();
if (defaultTab) {
navigateTo(defaultTab);
} else {
console.warn('用户没有新增退款和金币退款明细的权限');
// router.push({ name: 'noPermission' });
}
}
});
//
onMounted(() => {
//
if (route.path === '/coinRefund') {
const defaultTab = getDefaultRoute();
if (defaultTab) {
navigateTo(defaultTab);
} else {
// console.warn('退退');
router.push({ name: 'noPermission' });
}
} else {
//
if (route.name === routeMap.add && hasAddPermission.value) {
activeTab.value = 'add';
} else if (route.name === routeMap.detail && hasDetailPermission.value) {
activeTab.value = 'detail';
}
}
});
</script> </script>

99
src/views/usergold/clientCount.vue

@ -1,61 +1,104 @@
<template> <template>
<div> <div>
<!-- 这里放置标签切换的按钮 -->
<el-button-group> <el-button-group>
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button <el-button
:type="activeTab === 'detail' ? 'primary' : 'default'" :type="activeTab === 'detail' ? 'primary' : 'default'"
@click="goToDetail"
@click="navigateTo('detail')"
:disabled="!hasDetailPermission"
> >
金币明细 金币明细
</el-button> </el-button>
<el-button <el-button
:type="activeTab === 'balance' ? 'primary' : 'default'" :type="activeTab === 'balance' ? 'primary' : 'default'"
@click="goToBalance"
@click="navigateTo('balance')"
:disabled="!hasBalancePermission"
> >
金币余额 金币余额
</el-button> </el-button>
</el-button-group> </el-button-group>
<!-- 渲染子路由组件 -->
<router-view></router-view> <router-view></router-view>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue';
import { ref, watch, onMounted, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { storeToRefs } from 'pinia';
import { useAdminStore } from '@/store/index.js';
const router = useRouter();//
const route = useRoute();//
// activeTab
const activeTab = ref(route.name === 'clientCountBalance' ? 'balance' : 'detail');
//clientCountBalancebalancedetail
//clientCountDetaildetail
const router = useRouter();
const route = useRoute();
const adminStore = useAdminStore();
const { menuTree } = storeToRefs(adminStore);
//
const routeMap = {
detail: 'clientCountDetail',
balance: 'clientCountBalance'
};
const goToDetail = () => {
// activeTab detail
activeTab.value = 'detail';
router.push({ name: 'clientCountDetail' });
//
const activeTab = ref('');
//
const hasDetailPermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '金币明细' || menu.menuName === '客户账户明细'
);
});
//
const hasBalancePermission = computed(() => {
if (!menuTree.value) return false;
return menuTree.value.some(menu =>
menu.menuName === '金币余额' || menu.menuName === '客户账户明细'
);
});
//
const navigateTo = (tab) => {
//
if ((tab === 'detail' && !hasDetailPermission.value) ||
(tab === 'balance' && !hasBalancePermission.value)) {
return;
}
activeTab.value = tab;
router.push({ name: routeMap[tab] });
}; };
const goToBalance = () => {
// activeTab balance
activeTab.value = 'balance';
router.push({ name: 'clientCountBalance' });
//
const getDefaultRoute = () => {
if (hasDetailPermission.value) return 'detail';
if (hasBalancePermission.value) return 'balance';
return null;
}; };
// activeTab
//
watch(() => route.name, (newName) => { watch(() => route.name, (newName) => {
if (newName === 'clientCountDetail') {
if (newName === routeMap.detail && hasDetailPermission.value) {
activeTab.value = 'detail'; activeTab.value = 'detail';
} else if (newName === 'clientCountBalance') {
} else if (newName === routeMap.balance && hasBalancePermission.value) {
activeTab.value = 'balance'; activeTab.value = 'balance';
}});
}
});
//
// if (route.name === 'usergold') {
// router.push({ name: 'clientCountDetail' });
// }
//
onMounted(() => {
//
if (route.name === 'usergold') {
const defaultTab = getDefaultRoute();
if (defaultTab) {
navigateTo(defaultTab);
}
} else {
//
if (route.name === routeMap.detail) {
activeTab.value = 'detail';
} else if (route.name === routeMap.balance) {
activeTab.value = 'balance';
}
}
});
</script> </script>
Loading…
Cancel
Save