fix: login landing from menu_access, silent optional Layout 403

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-28 23:59:33 +08:00
parent 9e7dba32d2
commit 12506c5d32
7 changed files with 253 additions and 35 deletions

View File

@@ -256,18 +256,13 @@ import {
setMenuAccess,
getMenuAccess,
canSwitchClubByMenu,
shouldShowAllMenus,
ensureMenuAccess,
canShowMenuPage,
} from '@/utils/club-context'
const menuAccessState = ref(getMenuAccess())
const canShow = (pageId) => {
const access = menuAccessState.value ?? getMenuAccess()
if (shouldShowAllMenus(access)) return true
if (access.visible_page_ids.length === 0) return false
return access.visible_page_ids.includes(pageId)
}
const canShow = (pageId) => canShowMenuPage(pageId)
const { proxy } = getCurrentInstance()
const route = useRoute()
@@ -327,7 +322,7 @@ const loadMenuAccess = async () => {
const loadClubContext = async () => {
try {
const res = await request.get(JITUAN_API.meContext)
const res = await request.get(JITUAN_API.meContext, { skipErrorToast: true })
if (res.code === 0 && res.data) {
mergeServerClubContext(res.data)
clubOptions.value = res.data.clubs || []
@@ -386,7 +381,7 @@ const fetchStats = async () => {
try {
const res = await request.post('/yonghu/kfjrhqzl', {
phone: userPhone.value
}, { signal: abortController.signal })
}, { signal: abortController.signal, skipErrorToast: true })
if (res.code === 0) {
stats.value = res.data
}
@@ -427,7 +422,7 @@ const fetchKefuPermission = async () => {
try {
const res = await request.post('/houtai/kfhqltqx', {
phone: userPhone.value
})
}, { skipErrorToast: true })
if (res.code === 0) {
const { permissions, goeasy_appkey } = res.data
kefuPermissions.value = permissions || []

View File

@@ -65,7 +65,7 @@ import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { User, Lock, Key } from '@element-plus/icons-vue'
import axios from 'axios' // 直接使用 axios不经过封装的 request
import { JITUAN_API, setAdminClubContext, setMenuAccess } from '@/utils/club-context'
import { JITUAN_API, getDefaultLandingPath, setAdminClubContext, setMenuAccess } from '@/utils/club-context'
const router = useRouter()
const loading = ref(false)
@@ -123,9 +123,10 @@ const handleLogin = async () => {
} else if (res.data.menu_access) {
setMenuAccess(res.data.menu_access)
}
const ma = res.data.menu_access || {}
const landing = getDefaultLandingPath(ma)
ElMessage.success('登录成功')
const firstPath = res.data.menu_access?.visible_paths?.[0]
router.push(firstPath || '/order/platform')
router.push(landing || '/welcome')
} else if (res.code === 4) {
// 账号被封禁
ElMessage.error('账号已被封禁')

75
src/views/Welcome.vue Normal file
View File

@@ -0,0 +1,75 @@
<template>
<div class="welcome-page">
<el-result icon="warning" title="暂无可用功能菜单">
<template #sub-title>
<p v-if="yonghuid">用户ID{{ yonghuid }}</p>
<p v-if="roleNames.length">已绑角色{{ roleNames.join('') }}角色内可能未含功能权限码</p>
<p v-else>该账号未绑定任何角色</p>
<p class="hint">请超管在后台用户中为该用户ID绑定角色角色内需含对应权限考核=kaohepeizhi</p>
</template>
<template #extra>
<el-button type="primary" @click="goTry">刷新权限</el-button>
<el-button @click="logout">退出登录</el-button>
</template>
</el-result>
</div>
</template>
<script setup>
import { computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
import {
clearMenuAccess,
getDefaultLandingPath,
getMenuAccess,
JITUAN_API,
setMenuAccess,
} from '@/utils/club-context'
const router = useRouter()
const access = computed(() => getMenuAccess() || {})
const yonghuid = computed(() => access.value.yonghuid || '')
const roleNames = computed(() => access.value.role_names || [])
const goTry = async () => {
try {
const res = await request.get(JITUAN_API.menuAccess)
if (res.code === 0 && res.data) {
setMenuAccess(res.data)
const landing = getDefaultLandingPath(res.data)
if (landing) {
ElMessage.success('权限已生效')
router.replace(landing)
return
}
}
ElMessage.warning('仍无可用菜单,请确认角色与权限已绑定')
} catch {
ElMessage.error('刷新失败')
}
}
const logout = () => {
localStorage.removeItem('token')
clearMenuAccess()
router.replace('/login')
}
onMounted(() => {
const landing = getDefaultLandingPath()
if (landing) router.replace(landing)
})
</script>
<style scoped>
.welcome-page {
padding: 48px 24px;
}
.hint {
margin-top: 8px;
color: #909399;
font-size: 14px;
}
</style>

View File

@@ -51,6 +51,7 @@
<!-- 用户表格 -->
<el-table :data="userList" v-loading="loading" border class="user-table">
<el-table-column prop="phone" label="账号" width="140" />
<el-table-column prop="yonghuid" label="用户ID" width="100" />
<el-table-column prop="nicheng" label="昵称" width="150" />
<el-table-column label="角色" min-width="180">
<template #default="{ row }">
@@ -103,6 +104,9 @@
<div class="info-section">
<div class="section-title">基本信息</div>
<el-form :model="editForm" label-width="100px">
<el-form-item label="用户ID">
<span>{{ currentUser?.yonghuid }}</span>
</el-form-item>
<el-form-item label="账号">
<span>{{ currentUser?.phone }}</span>
</el-form-item>
@@ -386,6 +390,7 @@ const saveUserInfo = async () => {
const payload = {
username,
action: 'update_user_info',
yonghuid: currentUser.value.yonghuid,
phone: currentUser.value.phone,
nicheng: editForm.value.nicheng,
status: editForm.value.status
@@ -426,6 +431,7 @@ const confirmAddUserRoles = async () => {
const res = await request.post('/houtai/xghtyhsj', {
username,
action: 'add_user_roles',
yonghuid: currentUser.value.yonghuid,
phone: currentUser.value.phone,
role_codes: selectedRoleCodes.value
})
@@ -452,6 +458,7 @@ const removeUserRole = async (role) => {
const res = await request.post('/houtai/xghtyhsj', {
username,
action: 'remove_user_role',
yonghuid: currentUser.value.yonghuid,
phone: currentUser.value.phone,
role_code: role.role_code
})