feat(bugcollect): 将崩溃收集移为服务管理子菜单,并增加服务开通校验
- MainLayout: 移除独立的 bug-collect 顶级子菜单,改为嵌套在服务管理下的 services-bugcollect 子菜单(桌面 + 移动抽屉均已同步) - openedMenus: /bugcollect/* 路径下同时展开 services 和 services-bugcollect - FeatureService.serviceType: 补充 BUG_COLLECT 枚举值 - appApi.requestActivation: 支持 BUG_COLLECT 服务类型 - useBugCollectApp: 增加 gateStatus / serviceEnabled / checkingService;appKey 变化时自动调用 getServices 检查 BUG_COLLECT 是否已开通;提供 applyDialogVisible / submitActivation 申请流程 - 全部 7 个 BugCollect 视图: 替换原 !appKey 判断为 gateStatus 四态门控(no-app / loading / not-enabled / enabled),并附加申请开通对话框 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
2d650d2b7a
当前提交
fb5e9753a3
@ -27,7 +27,7 @@ export interface FeatureService {
|
||||
id: string
|
||||
appKey: string
|
||||
platform: 'ANDROID' | 'IOS' | 'HARMONY'
|
||||
serviceType: 'IM' | 'PUSH' | 'UPDATE' | 'LICENSE'
|
||||
serviceType: 'IM' | 'PUSH' | 'UPDATE' | 'LICENSE' | 'BUG_COLLECT'
|
||||
enabled: boolean
|
||||
config?: string | null
|
||||
createdAt: string
|
||||
@ -202,7 +202,7 @@ export const appApi = {
|
||||
regenerateConfigFile: (appKey: string) =>
|
||||
client.post<{ data: null }>(`/apps/${appKey}/config-file/regenerate`),
|
||||
|
||||
requestActivation: (appKey: string, serviceType: 'IM' | 'PUSH' | 'UPDATE' | 'LICENSE', reason: string) =>
|
||||
requestActivation: (appKey: string, serviceType: 'IM' | 'PUSH' | 'UPDATE' | 'LICENSE' | 'BUG_COLLECT', reason: string) =>
|
||||
client.post<{ data: null }>(`/apps/${appKey}/services/request-activation`, null, {
|
||||
params: { platform: 'ANDROID', serviceType, applyReason: reason },
|
||||
}),
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { appApi, type App } from '@/api/app'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const STORAGE_KEY = 'bugcollect_selected_app_key'
|
||||
|
||||
@ -10,6 +11,11 @@ export function useBugCollectApp() {
|
||||
const apps = ref<App[]>([])
|
||||
const loadingApps = ref(false)
|
||||
const selectedAppKey = ref(localStorage.getItem(STORAGE_KEY) ?? '')
|
||||
const serviceEnabled = ref<boolean | null>(null)
|
||||
const checkingService = ref(false)
|
||||
const applyDialogVisible = ref(false)
|
||||
const applyReason = ref('')
|
||||
const applyLoading = ref(false)
|
||||
|
||||
const appKey = computed(() => {
|
||||
const q = route.query.appKey
|
||||
@ -17,6 +23,13 @@ export function useBugCollectApp() {
|
||||
return selectedAppKey.value
|
||||
})
|
||||
|
||||
// 'no-app' | 'loading' | 'not-enabled' | 'enabled'
|
||||
const gateStatus = computed(() => {
|
||||
if (!appKey.value) return 'no-app'
|
||||
if (checkingService.value || serviceEnabled.value === null) return 'loading'
|
||||
return serviceEnabled.value ? 'enabled' : 'not-enabled'
|
||||
})
|
||||
|
||||
async function loadApps() {
|
||||
loadingApps.value = true
|
||||
try {
|
||||
@ -29,12 +42,49 @@ export function useBugCollectApp() {
|
||||
}
|
||||
}
|
||||
|
||||
async function checkService(key: string) {
|
||||
if (!key) {
|
||||
serviceEnabled.value = null
|
||||
return
|
||||
}
|
||||
checkingService.value = true
|
||||
serviceEnabled.value = null
|
||||
try {
|
||||
const res = await appApi.getServices(key)
|
||||
const found = (res.data.data ?? []).find(s => s.serviceType === 'BUG_COLLECT')
|
||||
serviceEnabled.value = found?.enabled ?? false
|
||||
} catch {
|
||||
serviceEnabled.value = false
|
||||
} finally {
|
||||
checkingService.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function setApp(key: string) {
|
||||
selectedAppKey.value = key
|
||||
localStorage.setItem(STORAGE_KEY, key)
|
||||
router.replace({ query: { ...route.query, appKey: key } })
|
||||
}
|
||||
|
||||
async function submitActivation() {
|
||||
if (!appKey.value || !applyReason.value.trim()) return
|
||||
applyLoading.value = true
|
||||
try {
|
||||
await appApi.requestActivation(appKey.value, 'BUG_COLLECT', applyReason.value.trim())
|
||||
ElMessage.success('申请已提交,请等待审核')
|
||||
applyDialogVisible.value = false
|
||||
applyReason.value = ''
|
||||
} catch {
|
||||
ElMessage.error('申请提交失败,请稍后重试')
|
||||
} finally {
|
||||
applyLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(appKey, (key) => {
|
||||
checkService(key)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
const q = route.query.appKey
|
||||
if (typeof q === 'string' && q.trim()) {
|
||||
@ -42,7 +92,20 @@ export function useBugCollectApp() {
|
||||
localStorage.setItem(STORAGE_KEY, q.trim())
|
||||
}
|
||||
loadApps()
|
||||
if (appKey.value) checkService(appKey.value)
|
||||
})
|
||||
|
||||
return { apps, loadingApps, appKey, setApp }
|
||||
return {
|
||||
apps,
|
||||
loadingApps,
|
||||
appKey,
|
||||
setApp,
|
||||
gateStatus,
|
||||
serviceEnabled,
|
||||
checkingService,
|
||||
applyDialogVisible,
|
||||
applyReason,
|
||||
applyLoading,
|
||||
submitActivation,
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,13 @@
|
||||
<el-option v-for="a in apps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-empty v-if="!appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="gateStatus === 'no-app'" description="请选择一个应用" style="margin-top:80px" />
|
||||
<div v-else-if="gateStatus === 'loading'" v-loading="true" style="min-height:200px" />
|
||||
<div v-else-if="gateStatus === 'not-enabled'" style="margin-top:60px;text-align:center">
|
||||
<el-empty description="当前应用未开通崩溃收集服务">
|
||||
<el-button type="primary" @click="applyDialogVisible = true">申请开通</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
<el-card shadow="never">
|
||||
@ -84,6 +90,13 @@
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
<el-dialog v-model="applyDialogVisible" title="申请开通崩溃收集" width="400px" :close-on-click-modal="false">
|
||||
<el-input v-model="applyReason" type="textarea" placeholder="请说明申请原因(选填)" :rows="3" />
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="applyLoading" @click="submitActivation">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -92,7 +105,7 @@ import { ref, onMounted } from 'vue'
|
||||
import { bugCollectApi, type BugCollectEventItem } from '@/api/bugcollect'
|
||||
import { useBugCollectApp } from '@/composables/useBugCollectApp'
|
||||
|
||||
const { apps, loadingApps, appKey, setApp } = useBugCollectApp()
|
||||
const { apps, loadingApps, appKey, setApp, gateStatus, applyDialogVisible, applyReason, applyLoading, submitActivation } = useBugCollectApp()
|
||||
|
||||
const events = ref<BugCollectEventItem[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -15,7 +15,13 @@
|
||||
<el-option v-for="a in apps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-empty v-if="!appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="gateStatus === 'no-app'" description="请选择一个应用" style="margin-top:80px" />
|
||||
<div v-else-if="gateStatus === 'loading'" v-loading="true" style="min-height:200px" />
|
||||
<div v-else-if="gateStatus === 'not-enabled'" style="margin-top:60px;text-align:center">
|
||||
<el-empty description="当前应用未开通崩溃收集服务">
|
||||
<el-button type="primary" @click="applyDialogVisible = true">申请开通</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
<el-card style="margin-bottom: 16px">
|
||||
@ -54,6 +60,13 @@
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
<el-dialog v-model="applyDialogVisible" title="申请开通崩溃收集" width="400px" :close-on-click-modal="false">
|
||||
<el-input v-model="applyReason" type="textarea" placeholder="请说明申请原因(选填)" :rows="3" />
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="applyLoading" @click="submitActivation">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -62,7 +75,7 @@ import { ref } from 'vue'
|
||||
import { bugCollectApi, type BugCollectFunnelStep } from '@/api/bugcollect'
|
||||
import { useBugCollectApp } from '@/composables/useBugCollectApp'
|
||||
|
||||
const { apps, loadingApps, appKey, setApp } = useBugCollectApp()
|
||||
const { apps, loadingApps, appKey, setApp, gateStatus, applyDialogVisible, applyReason, applyLoading, submitActivation } = useBugCollectApp()
|
||||
|
||||
const steps = ref(['', ''])
|
||||
const funnelData = ref<BugCollectFunnelStep[]>([])
|
||||
|
||||
@ -15,7 +15,13 @@
|
||||
<el-option v-for="a in apps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-empty v-if="!appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="gateStatus === 'no-app'" description="请选择一个应用" style="margin-top:80px" />
|
||||
<div v-else-if="gateStatus === 'loading'" v-loading="true" style="min-height:200px" />
|
||||
<div v-else-if="gateStatus === 'not-enabled'" style="margin-top:60px;text-align:center">
|
||||
<el-empty description="当前应用未开通崩溃收集服务">
|
||||
<el-button type="primary" @click="applyDialogVisible = true">申请开通</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
<el-card shadow="never">
|
||||
@ -83,6 +89,13 @@
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
<el-dialog v-model="applyDialogVisible" title="申请开通崩溃收集" width="400px" :close-on-click-modal="false">
|
||||
<el-input v-model="applyReason" type="textarea" placeholder="请说明申请原因(选填)" :rows="3" />
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="applyLoading" @click="submitActivation">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -91,7 +104,7 @@ import { ref, onMounted } from 'vue'
|
||||
import { bugCollectApi, type BugCollectIssue } from '@/api/bugcollect'
|
||||
import { useBugCollectApp } from '@/composables/useBugCollectApp'
|
||||
|
||||
const { apps, loadingApps, appKey, setApp } = useBugCollectApp()
|
||||
const { apps, loadingApps, appKey, setApp, gateStatus, applyDialogVisible, applyReason, applyLoading, submitActivation } = useBugCollectApp()
|
||||
|
||||
const issues = ref<BugCollectIssue[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -15,7 +15,13 @@
|
||||
<el-option v-for="a in apps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-empty v-if="!appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="gateStatus === 'no-app'" description="请选择一个应用" style="margin-top:80px" />
|
||||
<div v-else-if="gateStatus === 'loading'" v-loading="true" style="min-height:200px" />
|
||||
<div v-else-if="gateStatus === 'not-enabled'" style="margin-top:60px;text-align:center">
|
||||
<el-empty description="当前应用未开通崩溃收集服务">
|
||||
<el-button type="primary" @click="applyDialogVisible = true">申请开通</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
@ -94,6 +100,13 @@
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
<el-dialog v-model="applyDialogVisible" title="申请开通崩溃收集" width="400px" :close-on-click-modal="false">
|
||||
<el-input v-model="applyReason" type="textarea" placeholder="请说明申请原因(选填)" :rows="3" />
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="applyLoading" @click="submitActivation">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -103,7 +116,7 @@ import { bugCollectApi, type BugCollectOverview } from '@/api/bugcollect'
|
||||
import { Warning, Plus, User } from '@element-plus/icons-vue'
|
||||
import { useBugCollectApp } from '@/composables/useBugCollectApp'
|
||||
|
||||
const { apps, loadingApps, appKey, setApp } = useBugCollectApp()
|
||||
const { apps, loadingApps, appKey, setApp, gateStatus, applyDialogVisible, applyReason, applyLoading, submitActivation } = useBugCollectApp()
|
||||
|
||||
const overview = ref<BugCollectOverview>({
|
||||
totalIssues: 0,
|
||||
|
||||
@ -15,7 +15,13 @@
|
||||
<el-option v-for="a in apps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-empty v-if="!appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="gateStatus === 'no-app'" description="请选择一个应用" style="margin-top:80px" />
|
||||
<div v-else-if="gateStatus === 'loading'" v-loading="true" style="min-height:200px" />
|
||||
<div v-else-if="gateStatus === 'not-enabled'" style="margin-top:60px;text-align:center">
|
||||
<el-empty description="当前应用未开通崩溃收集服务">
|
||||
<el-button type="primary" @click="applyDialogVisible = true">申请开通</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
<el-card shadow="never">
|
||||
@ -44,6 +50,13 @@
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
<el-dialog v-model="applyDialogVisible" title="申请开通崩溃收集" width="400px" :close-on-click-modal="false">
|
||||
<el-input v-model="applyReason" type="textarea" placeholder="请说明申请原因(选填)" :rows="3" />
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="applyLoading" @click="submitActivation">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -52,7 +65,7 @@ import { ref, onMounted } from 'vue'
|
||||
import { bugCollectApi, type BugCollectIssueRanking } from '@/api/bugcollect'
|
||||
import { useBugCollectApp } from '@/composables/useBugCollectApp'
|
||||
|
||||
const { apps, loadingApps, appKey, setApp } = useBugCollectApp()
|
||||
const { apps, loadingApps, appKey, setApp, gateStatus, applyDialogVisible, applyReason, applyLoading, submitActivation } = useBugCollectApp()
|
||||
|
||||
const rankings = ref<BugCollectIssueRanking[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -15,7 +15,13 @@
|
||||
<el-option v-for="a in apps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-empty v-if="!appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="gateStatus === 'no-app'" description="请选择一个应用" style="margin-top:80px" />
|
||||
<div v-else-if="gateStatus === 'loading'" v-loading="true" style="min-height:200px" />
|
||||
<div v-else-if="gateStatus === 'not-enabled'" style="margin-top:60px;text-align:center">
|
||||
<el-empty description="当前应用未开通崩溃收集服务">
|
||||
<el-button type="primary" @click="applyDialogVisible = true">申请开通</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
<el-card shadow="never">
|
||||
@ -49,6 +55,13 @@
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
<el-dialog v-model="applyDialogVisible" title="申请开通崩溃收集" width="400px" :close-on-click-modal="false">
|
||||
<el-input v-model="applyReason" type="textarea" placeholder="请说明申请原因(选填)" :rows="3" />
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="applyLoading" @click="submitActivation">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -57,7 +70,7 @@ import { ref, onMounted } from 'vue'
|
||||
import { bugCollectApi, type BugCollectIssueRanking } from '@/api/bugcollect'
|
||||
import { useBugCollectApp } from '@/composables/useBugCollectApp'
|
||||
|
||||
const { apps, loadingApps, appKey, setApp } = useBugCollectApp()
|
||||
const { apps, loadingApps, appKey, setApp, gateStatus, applyDialogVisible, applyReason, applyLoading, submitActivation } = useBugCollectApp()
|
||||
|
||||
const rankings = ref<BugCollectIssueRanking[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -18,7 +18,13 @@
|
||||
<el-option v-for="a in apps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
||||
</el-select>
|
||||
</div>
|
||||
<el-empty v-if="!appKey" description="请选择一个应用" style="margin-top:80px" />
|
||||
<el-empty v-if="gateStatus === 'no-app'" description="请选择一个应用" style="margin-top:80px" />
|
||||
<div v-else-if="gateStatus === 'loading'" v-loading="true" style="min-height:200px" />
|
||||
<div v-else-if="gateStatus === 'not-enabled'" style="margin-top:60px;text-align:center">
|
||||
<el-empty description="当前应用未开通崩溃收集服务">
|
||||
<el-button type="primary" @click="applyDialogVisible = true">申请开通</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
<el-card shadow="never">
|
||||
@ -83,6 +89,13 @@
|
||||
<el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="applyDialogVisible" title="申请开通崩溃收集" width="400px" :close-on-click-modal="false">
|
||||
<el-input v-model="applyReason" type="textarea" placeholder="请说明申请原因(选填)" :rows="3" />
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="applyLoading" @click="submitActivation">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -92,7 +105,7 @@ import { ElMessage } from 'element-plus'
|
||||
import { bugCollectApi, type BugCollectWebhook } from '@/api/bugcollect'
|
||||
import { useBugCollectApp } from '@/composables/useBugCollectApp'
|
||||
|
||||
const { apps, loadingApps, appKey, setApp } = useBugCollectApp()
|
||||
const { apps, loadingApps, appKey, setApp, gateStatus, applyDialogVisible, applyReason, applyLoading, submitActivation } = useBugCollectApp()
|
||||
|
||||
const webhooks = ref<BugCollectWebhook[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -21,7 +21,16 @@
|
||||
<el-menu-item index="/services/push"><el-icon><Bell /></el-icon><span>离线推送</span></el-menu-item>
|
||||
<el-menu-item index="/services/update"><el-icon><Upload /></el-icon><span>版本管理</span></el-menu-item>
|
||||
<el-menu-item index="/services/license"><el-icon><Key /></el-icon><span>授权管理</span></el-menu-item>
|
||||
<el-menu-item index="/services/bugcollect"><el-icon><DataLine /></el-icon><span>崩溃收集</span></el-menu-item>
|
||||
<el-sub-menu index="services-bugcollect">
|
||||
<template #title><el-icon><DataLine /></el-icon><span>崩溃收集</span></template>
|
||||
<el-menu-item index="/bugcollect/overview"><el-icon><Odometer /></el-icon><span>概览</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/issues"><el-icon><Warning /></el-icon><span>错误列表</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/events"><el-icon><List /></el-icon><span>事件流水</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/funnels"><el-icon><Filter /></el-icon><span>漏斗分析</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/freq"><el-icon><Sort /></el-icon><span>高频排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/risk"><el-icon><Warning /></el-icon><span>高危排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/webhooks"><el-icon><Link /></el-icon><span>Webhook</span></el-menu-item>
|
||||
</el-sub-menu>
|
||||
</el-sub-menu>
|
||||
<el-menu-item index="/security"><el-icon><Lock /></el-icon><span>安全中心</span></el-menu-item>
|
||||
<el-sub-menu index="ops">
|
||||
@ -30,16 +39,6 @@
|
||||
<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-sub-menu index="bug-collect">
|
||||
<template #title><el-icon><DataLine /></el-icon><span>Bug收集</span></template>
|
||||
<el-menu-item index="/bugcollect/overview"><el-icon><Odometer /></el-icon><span>概览</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/issues"><el-icon><Warning /></el-icon><span>错误列表</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/events"><el-icon><List /></el-icon><span>事件流水</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/funnels"><el-icon><Filter /></el-icon><span>漏斗分析</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/freq"><el-icon><Sort /></el-icon><span>高频排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/risk"><el-icon><Warning /></el-icon><span>高危排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/webhooks"><el-icon><Link /></el-icon><span>Webhook</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>
|
||||
@ -72,7 +71,16 @@
|
||||
<el-menu-item index="/services/push"><el-icon><Bell /></el-icon><span>离线推送</span></el-menu-item>
|
||||
<el-menu-item index="/services/update"><el-icon><Upload /></el-icon><span>版本管理</span></el-menu-item>
|
||||
<el-menu-item index="/services/license"><el-icon><Key /></el-icon><span>授权管理</span></el-menu-item>
|
||||
<el-menu-item index="/services/bugcollect"><el-icon><DataLine /></el-icon><span>崩溃收集</span></el-menu-item>
|
||||
<el-sub-menu index="services-bugcollect">
|
||||
<template #title><el-icon><DataLine /></el-icon><span>崩溃收集</span></template>
|
||||
<el-menu-item index="/bugcollect/overview"><el-icon><Odometer /></el-icon><span>概览</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/issues"><el-icon><Warning /></el-icon><span>错误列表</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/events"><el-icon><List /></el-icon><span>事件流水</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/funnels"><el-icon><Filter /></el-icon><span>漏斗分析</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/freq"><el-icon><Sort /></el-icon><span>高频排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/risk"><el-icon><Warning /></el-icon><span>高危排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/webhooks"><el-icon><Link /></el-icon><span>Webhook</span></el-menu-item>
|
||||
</el-sub-menu>
|
||||
</el-sub-menu>
|
||||
<el-menu-item index="/security"><el-icon><Lock /></el-icon><span>安全中心</span></el-menu-item>
|
||||
<el-sub-menu index="ops">
|
||||
@ -81,16 +89,6 @@
|
||||
<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-sub-menu index="bug-collect">
|
||||
<template #title><el-icon><DataLine /></el-icon><span>Bug收集</span></template>
|
||||
<el-menu-item index="/bugcollect/overview"><el-icon><Odometer /></el-icon><span>概览</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/issues"><el-icon><Warning /></el-icon><span>错误列表</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/events"><el-icon><List /></el-icon><span>事件流水</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/funnels"><el-icon><Filter /></el-icon><span>漏斗分析</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/freq"><el-icon><Sort /></el-icon><span>高频排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/rank/risk"><el-icon><Warning /></el-icon><span>高危排行</span></el-menu-item>
|
||||
<el-menu-item index="/bugcollect/webhooks"><el-icon><Link /></el-icon><span>Webhook</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>
|
||||
@ -152,7 +150,7 @@ 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')
|
||||
if (route.path.startsWith('/bugcollect/')) menus.push('bug-collect')
|
||||
if (route.path.startsWith('/bugcollect/')) menus.push('services', 'services-bugcollect')
|
||||
return menus
|
||||
})
|
||||
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户