From fb5e9753a374d9699dfba2954f869cd46a6210c9 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Wed, 17 Jun 2026 05:25:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(bugcollect):=20=E5=B0=86=E5=B4=A9=E6=BA=83?= =?UTF-8?q?=E6=94=B6=E9=9B=86=E7=A7=BB=E4=B8=BA=E6=9C=8D=E5=8A=A1=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=AD=90=E8=8F=9C=E5=8D=95=EF=BC=8C=E5=B9=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9C=8D=E5=8A=A1=E5=BC=80=E9=80=9A=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- tenant-platform/src/api/app.ts | 4 +- .../src/composables/useBugCollectApp.ts | 67 ++++++++++++++++++- .../views/bug-collect/BugCollectEvents.vue | 17 ++++- .../views/bug-collect/BugCollectFunnels.vue | 17 ++++- .../views/bug-collect/BugCollectIssues.vue | 17 ++++- .../views/bug-collect/BugCollectOverview.vue | 17 ++++- .../views/bug-collect/BugCollectRankFreq.vue | 17 ++++- .../views/bug-collect/BugCollectRankRisk.vue | 17 ++++- .../views/bug-collect/BugCollectWebhooks.vue | 17 ++++- .../src/views/layout/MainLayout.vue | 44 ++++++------ 10 files changed, 193 insertions(+), 41 deletions(-) diff --git a/tenant-platform/src/api/app.ts b/tenant-platform/src/api/app.ts index 8b50b31..fd33b6f 100644 --- a/tenant-platform/src/api/app.ts +++ b/tenant-platform/src/api/app.ts @@ -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 }, }), diff --git a/tenant-platform/src/composables/useBugCollectApp.ts b/tenant-platform/src/composables/useBugCollectApp.ts index 77218f4..cb936f9 100644 --- a/tenant-platform/src/composables/useBugCollectApp.ts +++ b/tenant-platform/src/composables/useBugCollectApp.ts @@ -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([]) const loadingApps = ref(false) const selectedAppKey = ref(localStorage.getItem(STORAGE_KEY) ?? '') + const serviceEnabled = ref(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, + } } diff --git a/tenant-platform/src/views/bug-collect/BugCollectEvents.vue b/tenant-platform/src/views/bug-collect/BugCollectEvents.vue index ee240ab..2faf909 100644 --- a/tenant-platform/src/views/bug-collect/BugCollectEvents.vue +++ b/tenant-platform/src/views/bug-collect/BugCollectEvents.vue @@ -15,7 +15,13 @@ - + +
+
+ + 申请开通 + +
+ + + +
@@ -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([]) const loading = ref(false) diff --git a/tenant-platform/src/views/bug-collect/BugCollectFunnels.vue b/tenant-platform/src/views/bug-collect/BugCollectFunnels.vue index 33bad09..381045d 100644 --- a/tenant-platform/src/views/bug-collect/BugCollectFunnels.vue +++ b/tenant-platform/src/views/bug-collect/BugCollectFunnels.vue @@ -15,7 +15,13 @@ - + +
+
+ + 申请开通 + +
+ + + +
@@ -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([]) diff --git a/tenant-platform/src/views/bug-collect/BugCollectIssues.vue b/tenant-platform/src/views/bug-collect/BugCollectIssues.vue index 6237fa0..01f6c6c 100644 --- a/tenant-platform/src/views/bug-collect/BugCollectIssues.vue +++ b/tenant-platform/src/views/bug-collect/BugCollectIssues.vue @@ -15,7 +15,13 @@ - + +
+
+ + 申请开通 + +
+ + + +
@@ -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([]) const loading = ref(false) diff --git a/tenant-platform/src/views/bug-collect/BugCollectOverview.vue b/tenant-platform/src/views/bug-collect/BugCollectOverview.vue index a3f6058..ef300db 100644 --- a/tenant-platform/src/views/bug-collect/BugCollectOverview.vue +++ b/tenant-platform/src/views/bug-collect/BugCollectOverview.vue @@ -15,7 +15,13 @@ - + +
+
+ + 申请开通 + +
+ + + +
@@ -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({ totalIssues: 0, diff --git a/tenant-platform/src/views/bug-collect/BugCollectRankFreq.vue b/tenant-platform/src/views/bug-collect/BugCollectRankFreq.vue index 5f91699..0eb13fc 100644 --- a/tenant-platform/src/views/bug-collect/BugCollectRankFreq.vue +++ b/tenant-platform/src/views/bug-collect/BugCollectRankFreq.vue @@ -15,7 +15,13 @@ - + +
+
+ + 申请开通 + +
+ + + +
@@ -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([]) const loading = ref(false) diff --git a/tenant-platform/src/views/bug-collect/BugCollectRankRisk.vue b/tenant-platform/src/views/bug-collect/BugCollectRankRisk.vue index 7b63117..45665e4 100644 --- a/tenant-platform/src/views/bug-collect/BugCollectRankRisk.vue +++ b/tenant-platform/src/views/bug-collect/BugCollectRankRisk.vue @@ -15,7 +15,13 @@ - + +
+
+ + 申请开通 + +
+ + + +
@@ -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([]) const loading = ref(false) diff --git a/tenant-platform/src/views/bug-collect/BugCollectWebhooks.vue b/tenant-platform/src/views/bug-collect/BugCollectWebhooks.vue index 0375952..af41496 100644 --- a/tenant-platform/src/views/bug-collect/BugCollectWebhooks.vue +++ b/tenant-platform/src/views/bug-collect/BugCollectWebhooks.vue @@ -18,7 +18,13 @@ - + +
+
+ + 申请开通 + +
+ + + +
@@ -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([]) const loading = ref(false) diff --git a/tenant-platform/src/views/layout/MainLayout.vue b/tenant-platform/src/views/layout/MainLayout.vue index a54bbbc..579bf51 100644 --- a/tenant-platform/src/views/layout/MainLayout.vue +++ b/tenant-platform/src/views/layout/MainLayout.vue @@ -21,7 +21,16 @@ 离线推送 版本管理 授权管理 - 崩溃收集 + + + 概览 + 错误列表 + 事件流水 + 漏斗分析 + 高频排行 + 高危排行 + Webhook + 安全中心 @@ -30,16 +39,6 @@ 数据库管理 操作日志 - - - 概览 - 错误列表 - 事件流水 - 漏斗分析 - 高频排行 - 高危排行 - Webhook - 子账号管理 @@ -72,7 +71,16 @@ 离线推送 版本管理 授权管理 - 崩溃收集 + + + 概览 + 错误列表 + 事件流水 + 漏斗分析 + 高频排行 + 高危排行 + Webhook + 安全中心 @@ -81,16 +89,6 @@ 数据库管理 操作日志 - - - 概览 - 错误列表 - 事件流水 - 漏斗分析 - 高频排行 - 高危排行 - Webhook - 子账号管理 @@ -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 })