fix: 控制台加权限,登录跳转资产信息
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 7m4s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 7m4s
This commit is contained in:
@@ -56,11 +56,11 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { RoutesAlias } from '@/router/routesAlias'
|
import { RoutesAlias } from '@/router/routesAlias'
|
||||||
import { WEB_LINKS } from '@/utils/constants'
|
import { WEB_LINKS } from '@/utils/constants'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const popoverRef = ref()
|
const popoverRef = ref()
|
||||||
const { hasAuth } = useAuth()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
interface Application {
|
interface Application {
|
||||||
name: string
|
name: string
|
||||||
@@ -108,36 +108,48 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
if (hasAuth('dashboard:console')) {
|
const menus = userStore.menus.value || []
|
||||||
|
|
||||||
|
const hasMenuPermission = (permCode: string): boolean => {
|
||||||
|
const findMenu = (items: any[]): boolean => {
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.perm_code === permCode) return true
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
if (findMenu(item.children)) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return findMenu(menus)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMenuPermission('menu:dashboard')) {
|
||||||
apps.unshift({
|
apps.unshift({
|
||||||
name: '工作台',
|
name: '工作台',
|
||||||
description: '系统概览与数据统计',
|
description: '系统概览与数据统计',
|
||||||
icon: '',
|
icon: '',
|
||||||
iconColor: '#377dff',
|
iconColor: '#377dff',
|
||||||
path: RoutesAlias.Dashboard,
|
path: RoutesAlias.Dashboard
|
||||||
permission: 'dashboard:console'
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasAuth('dashboard:analysis')) {
|
if (hasMenuPermission('menu:analysis')) {
|
||||||
apps.unshift({
|
apps.unshift({
|
||||||
name: '分析页',
|
name: '分析页',
|
||||||
description: '数据分析与可视化',
|
description: '数据分析与可视化',
|
||||||
icon: '',
|
icon: '',
|
||||||
iconColor: '#ff3b30',
|
iconColor: '#ff3b30',
|
||||||
path: RoutesAlias.Analysis,
|
path: RoutesAlias.Analysis
|
||||||
permission: 'dashboard:analysis'
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasAuth('dashboard:ecommerce')) {
|
if (hasMenuPermission('menu:ecommerce')) {
|
||||||
apps.unshift({
|
apps.unshift({
|
||||||
name: '电子商务',
|
name: '电子商务',
|
||||||
description: '电商数据统计',
|
description: '电商数据统计',
|
||||||
icon: '',
|
icon: '',
|
||||||
iconColor: '#00b42a',
|
iconColor: '#00b42a',
|
||||||
path: RoutesAlias.Ecommerce,
|
path: RoutesAlias.Ecommerce
|
||||||
permission: 'dashboard:ecommerce'
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -274,12 +274,15 @@ async function processBackendMenu(router: Router): Promise<void> {
|
|||||||
/**
|
/**
|
||||||
* 合并默认菜单
|
* 合并默认菜单
|
||||||
* 将配置的默认菜单合并到后端返回的菜单中
|
* 将配置的默认菜单合并到后端返回的菜单中
|
||||||
|
* 注意: /dashboard 及其子路由(console/analysis/ecommerce)不再作为默认菜单强制显示
|
||||||
|
* 这些路由只有在后端 menus 中返回时才会显示
|
||||||
*/
|
*/
|
||||||
function mergeDefaultMenus(
|
function mergeDefaultMenus(
|
||||||
backendMenus: AppRouteRecord[],
|
backendMenus: AppRouteRecord[],
|
||||||
routeMap: Map<string, AppRouteRecord>
|
routeMap: Map<string, AppRouteRecord>
|
||||||
): AppRouteRecord[] {
|
): AppRouteRecord[] {
|
||||||
const defaultMenuPaths = ['/dashboard']
|
// 移除 /dashboard 作为默认菜单,现在仪表台路由完全由后端控制
|
||||||
|
const defaultMenuPaths: string[] = []
|
||||||
|
|
||||||
const defaultMenus: AppRouteRecord[] = defaultMenuPaths
|
const defaultMenus: AppRouteRecord[] = defaultMenuPaths
|
||||||
.map((path) => {
|
.map((path) => {
|
||||||
|
|||||||
@@ -12,6 +12,28 @@ export const router = createRouter({
|
|||||||
scrollBehavior: () => ({ left: 0, top: 0 }) // 滚动行为
|
scrollBehavior: () => ({ left: 0, top: 0 }) // 滚动行为
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 处理路由错误(Chunk 加载失败等)
|
||||||
|
router.onError((error) => {
|
||||||
|
const pattern = /Loading chunk (\d+) failed|Failed to fetch dynamically imported module|Couldn't resolve component/
|
||||||
|
const isChunkLoadFailed = error.message && pattern.test(error.message)
|
||||||
|
|
||||||
|
if (isChunkLoadFailed) {
|
||||||
|
const key = '__route_chunk_reload__'
|
||||||
|
const hasReloaded = sessionStorage.getItem(key)
|
||||||
|
|
||||||
|
if (!hasReloaded) {
|
||||||
|
console.warn('检测到 chunk 加载失败,尝试刷新页面...')
|
||||||
|
sessionStorage.setItem(key, '1')
|
||||||
|
window.location.reload()
|
||||||
|
} else {
|
||||||
|
console.error('页面刷新后仍然无法加载组件,请联系管理员')
|
||||||
|
sessionStorage.removeItem(key)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('[路由错误]:', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 初始化路由
|
// 初始化路由
|
||||||
export function initRouter(app: App<Element>): void {
|
export function initRouter(app: App<Element>): void {
|
||||||
configureNProgress() // 顶部进度条
|
configureNProgress() // 顶部进度条
|
||||||
|
|||||||
@@ -105,5 +105,5 @@ export enum RoutesAlias {
|
|||||||
Calendar = '/template/calendar' // 日历
|
Calendar = '/template/calendar' // 日历
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主页路由
|
// 主页路由 - 修改为资产信息页面
|
||||||
export const HOME_PAGE = RoutesAlias.Dashboard
|
export const HOME_PAGE = RoutesAlias.AssetInformation
|
||||||
|
|||||||
@@ -98,17 +98,13 @@ function checkDuplicateRoutes(routes: AppRouteRecord[], parentPath = ''): void {
|
|||||||
* 获取组件路径的字符串表示
|
* 获取组件路径的字符串表示
|
||||||
*/
|
*/
|
||||||
function getComponentPathString(component: any): string {
|
function getComponentPathString(component: any): string {
|
||||||
|
// 只处理字符串类型的组件路径
|
||||||
if (typeof component === 'string') {
|
if (typeof component === 'string') {
|
||||||
return component
|
return component
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对于其他别名路由,获取组件名称
|
// 对于函数类型的组件(懒加载),返回空字符串
|
||||||
for (const key in RoutesAlias) {
|
// 因为这些组件已经是有效的组件定义,不需要再次处理
|
||||||
if (RoutesAlias[key as keyof typeof RoutesAlias] === component) {
|
|
||||||
return `RoutesAlias.${key}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,9 +246,8 @@ function handleNormalRoute(
|
|||||||
routeName: string
|
routeName: string
|
||||||
): void {
|
): void {
|
||||||
if (component) {
|
if (component) {
|
||||||
const aliasComponent = RoutesAlias[
|
// 直接使用 loadComponent 加载组件
|
||||||
component as keyof typeof RoutesAlias
|
// component 参数是路由路径(如 "/system/role"),loadComponent 会将其转换为组件导入路径
|
||||||
] as unknown as RouteRecordRaw['component']
|
converted.component = loadComponent(component as string, routeName)
|
||||||
converted.component = aliasComponent || loadComponent(component as string, routeName)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
<!-- 设备专属字段 -->
|
<!-- 设备专属字段 -->
|
||||||
<template v-if="cardInfo?.asset_type === 'device'">
|
<template v-if="cardInfo?.asset_type === 'device'">
|
||||||
<ElDescriptionsItem label="IMEI">{{ cardInfo?.imei || '-' }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="IMEI">{{ cardInfo?.imei || '-' }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="设备类型">{{ cardInfo?.device_type || '-' }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="设备名称">{{ cardInfo?.device_name || '-' }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="店铺">{{ cardInfo?.shop_name || '-' }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="店铺">{{ cardInfo?.shop_name || '-' }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="设备状态">
|
<ElDescriptionsItem label="设备状态">
|
||||||
<ElTag :type="getAssetStatusType(cardInfo?.status)" size="small">
|
<ElTag :type="getAssetStatusType(cardInfo?.status)" size="small">
|
||||||
@@ -98,53 +98,47 @@
|
|||||||
{{ getRealNameStatusName(currentCard?.real_name_status) }}
|
{{ getRealNameStatusName(currentCard?.real_name_status) }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="实名认证策略">
|
<ElDescriptionsItem label="实名时间">{{
|
||||||
{{ getRealnamePolicyName(cardInfo?.realname_policy) }}
|
cardInfo?.real_name_at ? formatDateTime(cardInfo.real_name_at) : '-'
|
||||||
</ElDescriptionsItem>
|
}}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="设备名称">{{ cardInfo?.device_name || '-' }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="设备类型">{{ cardInfo?.device_type || '-' }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="在线状态">
|
<ElDescriptionsItem label="在线状态">
|
||||||
<ElTag :type="getOnlineStatusType(cardInfo?.online_status)" size="small">
|
<ElTag :type="getOnlineStatusType(cardInfo?.online_status)" size="small">
|
||||||
{{ getOnlineStatusName(cardInfo?.online_status) }}
|
{{ getOnlineStatusName(cardInfo?.online_status) }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
|
|
||||||
<ElDescriptionsItem label="虚拟号">{{ cardInfo?.virtual_no || '-' }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="虚拟号">{{ cardInfo?.virtual_no || '-' }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="SN">{{ cardInfo?.sn || '-' }}</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="设备型号">{{
|
|
||||||
cardInfo?.device_model || '-'
|
|
||||||
}}</ElDescriptionsItem>
|
|
||||||
|
|
||||||
<ElDescriptionsItem label="供应商">{{ cardInfo?.supplier || '-' }}</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="已绑定卡数">{{
|
|
||||||
cardInfo?.bound_card_count || 0
|
|
||||||
}}</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="最大卡槽数">{{
|
|
||||||
cardInfo?.max_sim_slots || '-'
|
|
||||||
}}</ElDescriptionsItem>
|
|
||||||
|
|
||||||
<ElDescriptionsItem label="激活时间">{{
|
<ElDescriptionsItem label="激活时间">{{
|
||||||
cardInfo?.activated_at || '-'
|
cardInfo?.activated_at || '-'
|
||||||
}}</ElDescriptionsItem>
|
}}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="实名时间">{{
|
<ElDescriptionsItem label="切卡模式">{{
|
||||||
cardInfo?.real_name_at ? formatDateTime(cardInfo.real_name_at) : '-'
|
getSwitchModeName(cardInfo?.switch_mode)
|
||||||
}}</ElDescriptionsItem>
|
}}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="信号强度">
|
<ElDescriptionsItem label="信号强度">
|
||||||
<ElTag :type="getSignalStrengthType()" size="small">
|
<ElTag :type="getSignalStrengthType()" size="small">
|
||||||
{{ calculateSignalStrength() }}
|
{{ calculateSignalStrength() }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="已绑定卡数">{{
|
||||||
<ElDescriptionsItem label="切卡模式">{{
|
cardInfo?.bound_card_count || 0
|
||||||
getSwitchModeName(cardInfo?.switch_mode)
|
|
||||||
}}</ElDescriptionsItem>
|
}}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="最大卡槽数">{{
|
||||||
|
cardInfo?.max_sim_slots || '-'
|
||||||
|
}}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="实名认证策略">
|
||||||
|
{{ getRealnamePolicyName(cardInfo?.realname_policy) }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="设备型号">{{
|
||||||
|
cardInfo?.device_model || '-'
|
||||||
|
}}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="制造商">{{ cardInfo?.manufacturer || '-' }}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="最后在线时间">{{
|
<ElDescriptionsItem label="最后在线时间">{{
|
||||||
formatDateTime(cardInfo?.last_online_time) || '-'
|
formatDateTime(cardInfo?.last_online_time) || '-'
|
||||||
}}</ElDescriptionsItem>
|
}}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="最后同步时间">{{
|
<ElDescriptionsItem label="最后同步时间">{{
|
||||||
formatDateTime(cardInfo?.last_gateway_sync_at) || '-'
|
formatDateTime(cardInfo?.last_gateway_sync_at) || '-'
|
||||||
}}</ElDescriptionsItem>
|
}}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="制造商">{{ cardInfo?.manufacturer || '-' }}</ElDescriptionsItem>
|
<ElDescriptionsItem label="SN">{{ cardInfo?.sn || '-' }}</ElDescriptionsItem>
|
||||||
</template>
|
</template>
|
||||||
</ElDescriptions>
|
</ElDescriptions>
|
||||||
|
|
||||||
@@ -254,11 +248,6 @@
|
|||||||
{{ deviceRealtime.online_status === 1 ? '在线' : '离线' }}
|
{{ deviceRealtime.online_status === 1 ? '在线' : '离线' }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="设备状态">
|
|
||||||
<ElTag :type="deviceRealtime.status === 1 ? 'success' : 'info'" size="small">
|
|
||||||
{{ deviceRealtime.status === 1 ? '正常' : '禁用' }}
|
|
||||||
</ElTag>
|
|
||||||
</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="电量">
|
<ElDescriptionsItem label="电量">
|
||||||
{{
|
{{
|
||||||
deviceRealtime.battery_level !== null && deviceRealtime.battery_level !== undefined
|
deviceRealtime.battery_level !== null && deviceRealtime.battery_level !== undefined
|
||||||
@@ -288,15 +277,11 @@
|
|||||||
<ElDescriptionsItem label="接收质量(RSRQ)">
|
<ElDescriptionsItem label="接收质量(RSRQ)">
|
||||||
{{ deviceRealtime.rsrq ? `${deviceRealtime.rsrq} dB` : '-' }}
|
{{ deviceRealtime.rsrq ? `${deviceRealtime.rsrq} dB` : '-' }}
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
|
|
||||||
<ElDescriptionsItem label="信噪比(SINR)">
|
<ElDescriptionsItem label="信噪比(SINR)">
|
||||||
{{ deviceRealtime.sinr ? `${deviceRealtime.sinr} dB` : '-' }}
|
{{ deviceRealtime.sinr ? `${deviceRealtime.sinr} dB` : '-' }}
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="最大客户端数">
|
<ElDescriptionsItem label="已连接设备数">
|
||||||
{{ deviceRealtime.max_clients || '-' }}
|
{{ deviceRealtime.client_number }} / {{ deviceRealtime.max_clients }}
|
||||||
</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="当前使用ICCID">
|
|
||||||
{{ deviceRealtime.current_iccid || '-' }}
|
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
|
|
||||||
<!-- WiFi 信息 -->
|
<!-- WiFi 信息 -->
|
||||||
@@ -326,9 +311,6 @@
|
|||||||
<ElDescriptionsItem label="MAC 地址">
|
<ElDescriptionsItem label="MAC 地址">
|
||||||
{{ deviceRealtime.mac_address || '-' }}
|
{{ deviceRealtime.mac_address || '-' }}
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="IMEI">
|
|
||||||
{{ deviceRealtime.imei || '-' }}
|
|
||||||
</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="IMSI">
|
<ElDescriptionsItem label="IMSI">
|
||||||
{{ deviceRealtime.imsi || '-' }}
|
{{ deviceRealtime.imsi || '-' }}
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
@@ -353,9 +335,6 @@
|
|||||||
<ElDescriptionsItem label="上报周期">
|
<ElDescriptionsItem label="上报周期">
|
||||||
{{ deviceRealtime.sync_interval ? `${deviceRealtime.sync_interval} 秒` : '-' }}
|
{{ deviceRealtime.sync_interval ? `${deviceRealtime.sync_interval} 秒` : '-' }}
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="设备ID">
|
|
||||||
{{ deviceRealtime.device_id || '-' }}
|
|
||||||
</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="信息更新时间">
|
<ElDescriptionsItem label="信息更新时间">
|
||||||
{{ formatDateTime(deviceRealtime.last_update_time) || '-' }}
|
{{ formatDateTime(deviceRealtime.last_update_time) || '-' }}
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
|
|||||||
@@ -318,7 +318,6 @@ export function useAssetInfo() {
|
|||||||
// 设备实时信息(Gateway 数据)
|
// 设备实时信息(Gateway 数据)
|
||||||
if (data.device_realtime !== undefined) {
|
if (data.device_realtime !== undefined) {
|
||||||
deviceRealtime.value = data.device_realtime
|
deviceRealtime.value = data.device_realtime
|
||||||
console.log('设备实时信息:', deviceRealtime.value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@
|
|||||||
:total="pagination.total"
|
:total="pagination.total"
|
||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
:actions="getActions"
|
:actions="getActions"
|
||||||
:actionsWidth="120"
|
:inlineActionsCount="2"
|
||||||
|
:actionsWidth="200"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
>
|
>
|
||||||
@@ -126,14 +127,14 @@
|
|||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="confirmPayDialogVisible"
|
v-model="confirmPayDialogVisible"
|
||||||
title="确认线下充值"
|
title="确认线下充值"
|
||||||
width="400px"
|
width="25%"
|
||||||
@closed="handleConfirmPayDialogClosed"
|
@closed="handleConfirmPayDialogClosed"
|
||||||
>
|
>
|
||||||
<ElForm
|
<ElForm
|
||||||
ref="confirmPayFormRef"
|
ref="confirmPayFormRef"
|
||||||
:model="confirmPayForm"
|
:model="confirmPayForm"
|
||||||
:rules="confirmPayRules"
|
:rules="confirmPayRules"
|
||||||
label-width="100px"
|
label-width="80"
|
||||||
>
|
>
|
||||||
<ElFormItem label="充值单号">
|
<ElFormItem label="充值单号">
|
||||||
<span>{{ currentRecharge?.recharge_no }}</span>
|
<span>{{ currentRecharge?.recharge_no }}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user