feat(ui): 添加服务应用切换记忆功能并优化菜单结构
- 在IM、授权、推送、版本管理视图中添加最近使用应用的记忆功能 - 新增serviceApp工具函数用于存储和获取最近使用的应用 - 将系统日志、数据库、操作日志菜单项归类到运维管理子菜单 - 修复实体类索引字段命名不一致问题 - 在安全配置中启用方法级别安全注解支持
这个提交包含在:
父节点
db3158d2e4
当前提交
62966dcf20
@ -0,0 +1,17 @@
|
||||
const PREFIX = 'xqm_last_service_app_'
|
||||
|
||||
export function saveLastServiceApp(service: string, appKey: string) {
|
||||
try {
|
||||
localStorage.setItem(`${PREFIX}${service}`, appKey)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
export function getLastServiceApp(service: string): string | null {
|
||||
try {
|
||||
return localStorage.getItem(`${PREFIX}${service}`)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
@ -820,6 +820,7 @@ import { appApi, type App } from '@/api/app'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import { getLastServiceApp, saveLastServiceApp } from '@/utils/serviceApp'
|
||||
import {
|
||||
imAdminApi,
|
||||
type GlobalMute,
|
||||
@ -1346,6 +1347,7 @@ function resetMessageSearch() {
|
||||
}
|
||||
|
||||
function switchApp(val: string) {
|
||||
saveLastServiceApp('im', val)
|
||||
router.push(`/services/im/${val}`)
|
||||
}
|
||||
|
||||
@ -2002,7 +2004,14 @@ watch(appKey, (key) => {
|
||||
|
||||
onMounted(() => {
|
||||
if (isServicesPortal.value) {
|
||||
appApi.list().then(res => { portalApps.value = res.data.data })
|
||||
appApi.list().then(res => {
|
||||
portalApps.value = res.data.data
|
||||
if (!appKey.value && portalApps.value.length) {
|
||||
const saved = getLastServiceApp('im')
|
||||
const target = saved && portalApps.value.some(a => a.appKey === saved) ? saved : portalApps.value[0].appKey
|
||||
switchApp(target)
|
||||
}
|
||||
})
|
||||
if (!appKey.value) return
|
||||
checkServiceEnabled(appKey.value)
|
||||
return
|
||||
|
||||
@ -23,9 +23,12 @@
|
||||
<el-menu-item index="/services/license"><el-icon><Key /></el-icon><span>授权管理</span></el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item index="/security"><el-icon><Lock /></el-icon><span>安全中心</span></el-menu-item>
|
||||
<el-sub-menu index="ops">
|
||||
<template #title><el-icon><Setting /></el-icon><span>运维管理</span></template>
|
||||
<el-menu-item v-if="isPrivateDeploy" index="/system-logs"><el-icon><Monitor /></el-icon><span>服务日志</span></el-menu-item>
|
||||
<el-menu-item v-if="isPrivateDeploy" index="/database"><el-icon><Coin /></el-icon><span>数据库管理</span></el-menu-item>
|
||||
<el-menu-item index="/operation-logs"><el-icon><Document /></el-icon><span>操作日志</span></el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-if="auth.user?.type === 'MAIN'" index="/accounts"><el-icon><User /></el-icon><span>子账号管理</span></el-menu-item>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
@ -60,9 +63,12 @@
|
||||
<el-menu-item index="/services/license"><el-icon><Key /></el-icon><span>授权管理</span></el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item index="/security"><el-icon><Lock /></el-icon><span>安全中心</span></el-menu-item>
|
||||
<el-sub-menu index="ops">
|
||||
<template #title><el-icon><Setting /></el-icon><span>运维管理</span></template>
|
||||
<el-menu-item v-if="isPrivateDeploy" index="/system-logs"><el-icon><Monitor /></el-icon><span>服务日志</span></el-menu-item>
|
||||
<el-menu-item v-if="isPrivateDeploy" index="/database"><el-icon><Coin /></el-icon><span>数据库管理</span></el-menu-item>
|
||||
<el-menu-item index="/operation-logs"><el-icon><Document /></el-icon><span>操作日志</span></el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-if="auth.user?.type === 'MAIN'" index="/accounts"><el-icon><User /></el-icon><span>子账号管理</span></el-menu-item>
|
||||
</el-menu>
|
||||
</el-drawer>
|
||||
@ -110,7 +116,7 @@
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { Bell, ChatDotRound, Coin, Document, Grid, Key, List, Lock, Menu, Monitor, Odometer, Upload, User } from '@element-plus/icons-vue'
|
||||
import { Bell, ChatDotRound, Coin, Document, Grid, Key, List, Lock, Menu, Monitor, Odometer, Setting, Upload, User } from '@element-plus/icons-vue'
|
||||
import { getDeploymentStatus } from '@/api/system'
|
||||
|
||||
const auth = useAuthStore()
|
||||
@ -120,9 +126,12 @@ const isMobile = ref(false)
|
||||
const drawerVisible = ref(false)
|
||||
const isPrivateDeploy = ref(false)
|
||||
|
||||
const openedMenus = computed(() =>
|
||||
route.path.startsWith('/services/') ? ['services'] : [],
|
||||
)
|
||||
const openedMenus = computed(() => {
|
||||
const menus: string[] = []
|
||||
if (route.path.startsWith('/services/')) menus.push('services')
|
||||
if (['/system-logs', '/database', '/operation-logs'].includes(route.path)) menus.push('ops')
|
||||
return menus
|
||||
})
|
||||
|
||||
function updateViewport() {
|
||||
isMobile.value = window.innerWidth < 768
|
||||
|
||||
@ -151,6 +151,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { licenseApi, type AppLicense, type LicenseDevice } from '@/api/license'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import { getLastServiceApp, saveLastServiceApp } from '@/utils/serviceApp'
|
||||
import {
|
||||
connectServiceActivationRealtime,
|
||||
disconnectServiceActivationRealtime,
|
||||
@ -304,6 +305,7 @@ async function submitActivation() {
|
||||
}
|
||||
|
||||
function switchApp(key: string) {
|
||||
saveLastServiceApp('license', key)
|
||||
router.push(`/services/license/${key}`)
|
||||
}
|
||||
|
||||
@ -342,6 +344,11 @@ onMounted(() => {
|
||||
appApi.list().then(res => {
|
||||
portalApps.value = res.data.data || []
|
||||
currentApp.value = portalApps.value.find(item => item.appKey === appKey.value) ?? currentApp.value
|
||||
if (!appKey.value && portalApps.value.length) {
|
||||
const saved = getLastServiceApp('license')
|
||||
const target = saved && portalApps.value.some(a => a.appKey === saved) ? saved : portalApps.value[0].appKey
|
||||
switchApp(target)
|
||||
}
|
||||
})
|
||||
if (appKey.value) checkServiceEnabled(appKey.value)
|
||||
} else {
|
||||
|
||||
@ -174,6 +174,7 @@ import { ElMessage } from 'element-plus'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { pushAdminApi, type DeviceLoginLog, type TestPushResult, type UserPushStatus } from '@/api/push'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import { getLastServiceApp, saveLastServiceApp } from '@/utils/serviceApp'
|
||||
import {
|
||||
connectServiceActivationRealtime,
|
||||
disconnectServiceActivationRealtime,
|
||||
@ -243,6 +244,7 @@ const logsTotal = ref(0)
|
||||
const logsTotalPages = ref(0)
|
||||
|
||||
function switchApp(val: string) {
|
||||
saveLastServiceApp('push', val)
|
||||
router.push(`/services/push/${val}`)
|
||||
}
|
||||
|
||||
@ -326,7 +328,14 @@ watch(appKey, (key) => {
|
||||
|
||||
onMounted(() => {
|
||||
if (isServicesPortal.value) {
|
||||
appApi.list().then(res => { portalApps.value = res.data.data })
|
||||
appApi.list().then(res => {
|
||||
portalApps.value = res.data.data
|
||||
if (!appKey.value && portalApps.value.length) {
|
||||
const saved = getLastServiceApp('push')
|
||||
const target = saved && portalApps.value.some(a => a.appKey === saved) ? saved : portalApps.value[0].appKey
|
||||
switchApp(target)
|
||||
}
|
||||
})
|
||||
if (appKey.value) {
|
||||
checkServiceEnabled()
|
||||
}
|
||||
|
||||
@ -939,6 +939,7 @@ import { CircleCheckFilled, Delete, Document, Edit, Loading, UploadFilled, Warni
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { fileApi } from '@/api/file'
|
||||
import { formatTime } from '@/utils/date'
|
||||
import { getLastServiceApp, saveLastServiceApp } from '@/utils/serviceApp'
|
||||
import {
|
||||
updateAdminApi,
|
||||
type AppPackageInspectResult,
|
||||
@ -1359,6 +1360,7 @@ async function loadStoreConfigs() {
|
||||
}
|
||||
|
||||
function switchApp(val: string) {
|
||||
saveLastServiceApp('update', val)
|
||||
router.push(`/services/update/${val}`)
|
||||
}
|
||||
|
||||
@ -2488,7 +2490,14 @@ onMounted(() => {
|
||||
updateViewport()
|
||||
window.addEventListener('resize', updateViewport)
|
||||
if (isServicesPortal.value) {
|
||||
appApi.list().then(res => { portalApps.value = res.data.data })
|
||||
appApi.list().then(res => {
|
||||
portalApps.value = res.data.data
|
||||
if (!appKey.value && portalApps.value.length) {
|
||||
const saved = getLastServiceApp('update')
|
||||
const target = saved && portalApps.value.some(a => a.appKey === saved) ? saved : portalApps.value[0].appKey
|
||||
switchApp(target)
|
||||
}
|
||||
})
|
||||
if (!appKey.value) return
|
||||
checkServiceEnabled()
|
||||
}
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户