diff --git a/ops-platform/components.d.ts b/ops-platform/components.d.ts index 1daf8d2..d6e5a5e 100644 --- a/ops-platform/components.d.ts +++ b/ops-platform/components.d.ts @@ -16,6 +16,7 @@ declare module 'vue' { ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] ElDialog: typeof import('element-plus/es')['ElDialog'] ElDrawer: typeof import('element-plus/es')['ElDrawer'] + ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElForm: typeof import('element-plus/es')['ElForm'] ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElHeader: typeof import('element-plus/es')['ElHeader'] diff --git a/ops-platform/src/api/ops.ts b/ops-platform/src/api/ops.ts index d08a59c..e9eb093 100644 --- a/ops-platform/src/api/ops.ts +++ b/ops-platform/src/api/ops.ts @@ -131,6 +131,64 @@ export interface SensitiveWordPage { totalPages: number } +export interface PushDeviceInfo { + id: string + vendor: string + tokenPreview: string + platform?: string + deviceId: string + brand?: string + model?: string + osVersion?: string + appVersion?: string + receivePush: boolean + lastLoginAt: string + updatedAt: string +} + +export interface PushDiagnostics { + tokenType: 'PUSH' | 'IM' | 'UNKNOWN' + appId?: string + userId?: string + online: boolean + lastSeenAt: number + canSendOfflineMessage: boolean + deliverableDevice?: PushDeviceInfo | null + deliverableDevices: PushDeviceInfo[] + devices: PushDeviceInfo[] +} + +export interface PushDeviceLog { + id: string + appId: string + userId: string + vendor: string + tokenPreview: string + platform?: string + deviceId: string + brand?: string + model?: string + osVersion?: string + appVersion?: string + receivePush: boolean + eventType: 'REGISTER' | 'UNREGISTER' | 'RECEIVE_PUSH_UPDATE' + createdAt: string +} + +export interface PushDeviceLogPage { + content: PushDeviceLog[] + total: number + totalPages: number +} + +export interface PushTestResult { + appId: string + userId: string + sent: boolean + targetCount: number + targets: PushDeviceInfo[] +} + export const opsApi = { listTenants: (keyword = '', page = 0, size = 20) => client.get<{ data: TenantPage }>('/ops/tenants', { params: { keyword, page, size } }), @@ -189,4 +247,13 @@ export const opsApi = { deleteSensitiveWord: (id: string) => client.delete(`/ops/risk/sensitive-words/${id}`), + + searchPushByToken: (token: string, appId = '') => + client.get<{ data: PushDiagnostics }>('/ops/push/search', { params: { token, appId } }), + + listPushDeviceLogs: (appId: string, userId: string, page = 0, size = 20) => + client.get<{ data: PushDeviceLogPage }>('/ops/push/device-logs', { params: { appId, userId, page, size } }), + + sendPushTestOffline: (payload: { appId: string; userId: string; title: string; body: string; payload?: string }) => + client.post<{ data: PushTestResult }>('/ops/push/test-offline', payload), } diff --git a/ops-platform/src/router/index.ts b/ops-platform/src/router/index.ts index 719b83e..422c1e7 100644 --- a/ops-platform/src/router/index.ts +++ b/ops-platform/src/router/index.ts @@ -16,6 +16,7 @@ const router = createRouter({ { path: 'service-requests', component: () => import('@/views/services/ServiceRequestsView.vue') }, { path: 'apps', component: () => import('@/views/apps/AppListView.vue') }, { path: 'apps/:id', component: () => import('@/views/apps/AppDetailView.vue') }, + { path: 'push', component: () => import('@/views/push/PushDiagnosticsView.vue') }, { path: 'operation-logs', component: () => import('@/views/logs/OperationLogView.vue') }, { path: 'risk-control', component: () => import('@/views/risk/RiskControlView.vue') }, ], diff --git a/ops-platform/src/views/layout/MainLayout.vue b/ops-platform/src/views/layout/MainLayout.vue index bdc691e..9dba907 100644 --- a/ops-platform/src/views/layout/MainLayout.vue +++ b/ops-platform/src/views/layout/MainLayout.vue @@ -66,7 +66,7 @@ + + diff --git a/tenant-platform/src/api/app.ts b/tenant-platform/src/api/app.ts index 3642ea4..d781fec 100644 --- a/tenant-platform/src/api/app.ts +++ b/tenant-platform/src/api/app.ts @@ -116,7 +116,7 @@ export const appApi = { appId: string, platform: string, serviceType: string, - config: Partial & Partial & Partial, + config: Partial & Partial & Partial | Record, ) => client.put<{ data: FeatureService }>(`/apps/${appId}/services/config`, config, { params: { platform, serviceType }, diff --git a/tenant-platform/src/views/push/PushConfigView.vue b/tenant-platform/src/views/push/PushConfigView.vue index 2945a73..5da6411 100644 --- a/tenant-platform/src/views/push/PushConfigView.vue +++ b/tenant-platform/src/views/push/PushConfigView.vue @@ -50,8 +50,7 @@ @@ -78,7 +77,7 @@ type VendorKey = keyof PushServiceConfig type FieldDef = { key: string label: string - type?: 'password' | 'textarea' | 'switch' + type?: 'textarea' | 'switch' placeholder?: string rows?: number } @@ -117,7 +116,7 @@ const vendorDefs: VendorDef[] = [ hint: '填写 AppId / AppSecret,供服务端推送使用。', fields: [ { key: 'appId', label: 'AppId' }, - { key: 'appSecret', label: 'AppSecret', type: 'password' }, + { key: 'appSecret', label: 'AppSecret' }, ], }, { @@ -127,7 +126,7 @@ const vendorDefs: VendorDef[] = [ fields: [ { key: 'appId', label: 'AppId' }, { key: 'appKey', label: 'AppKey' }, - { key: 'appSecret', label: 'AppSecret', type: 'password' }, + { key: 'appSecret', label: 'AppSecret' }, ], }, { @@ -137,7 +136,7 @@ const vendorDefs: VendorDef[] = [ fields: [ { key: 'appId', label: 'AppId' }, { key: 'appKey', label: 'AppKey' }, - { key: 'masterSecret', label: 'MasterSecret', type: 'password' }, + { key: 'masterSecret', label: 'MasterSecret' }, ], }, { @@ -147,7 +146,7 @@ const vendorDefs: VendorDef[] = [ fields: [ { key: 'appId', label: 'AppId' }, { key: 'appKey', label: 'AppKey' }, - { key: 'appSecret', label: 'AppSecret', type: 'password' }, + { key: 'appSecret', label: 'AppSecret' }, ], }, { @@ -157,7 +156,7 @@ const vendorDefs: VendorDef[] = [ fields: [ { key: 'appId', label: 'AppId' }, { key: 'clientId', label: 'ClientId' }, - { key: 'clientSecret', label: 'ClientSecret', type: 'password' }, + { key: 'clientSecret', label: 'ClientSecret' }, ], }, { @@ -212,7 +211,7 @@ async function saveConfig() { if (!app.value) return saving.value = true try { - await appApi.updateServiceConfig(app.value.id, servicePlatform.value, 'PUSH', pushConfig) + await appApi.updateServiceConfig(app.value.id, servicePlatform.value, 'PUSH', toPushConfigRequest()) ElMessage.success('推送配置已保存') await loadData() } catch { @@ -222,6 +221,31 @@ async function saveConfig() { } } +function toPushConfigRequest(): Record { + return { + huaweiAppId: pushConfig.huawei.appId ?? '', + huaweiAppSecret: pushConfig.huawei.appSecret ?? '', + xiaomiAppId: pushConfig.xiaomi.appId ?? '', + xiaomiAppKey: pushConfig.xiaomi.appKey ?? '', + xiaomiAppSecret: pushConfig.xiaomi.appSecret ?? '', + oppoAppId: pushConfig.oppo.appId ?? '', + oppoAppKey: pushConfig.oppo.appKey ?? '', + oppoMasterSecret: pushConfig.oppo.masterSecret ?? '', + vivoAppId: pushConfig.vivo.appId ?? '', + vivoAppKey: pushConfig.vivo.appKey ?? '', + vivoAppSecret: pushConfig.vivo.appSecret ?? '', + honorAppId: pushConfig.honor.appId ?? '', + honorClientId: pushConfig.honor.clientId ?? '', + honorClientSecret: pushConfig.honor.clientSecret ?? '', + apnsTeamId: pushConfig.apns.teamId ?? '', + apnsKeyId: pushConfig.apns.keyId ?? '', + apnsBundleId: pushConfig.apns.bundleId ?? '', + apnsKeyPath: pushConfig.apns.keyPath ?? '', + apnsSandbox: pushConfig.apns.sandbox ?? false, + fcmServiceAccountJson: pushConfig.fcm.serviceAccountJson ?? '', + } +} + async function onTogglePushService(enable: boolean) { if (enable) { ElMessage.info('请通过服务开通流程启用推送服务')