feat(push): 添加多厂商推送集成支持
- 实现了华为 HMS 推送服务集成 - 实现了小米推送服务集成 - 实现了 OPPO 推送服务集成 - 实现了 vivo 推送服务集成 - 实现了荣耀推送服务集成 - 实现了 FCM 推送服务集成 - 添加了统一的厂商推送接口和检测机制 - 添加了推送配置 API 和存储管理 - 添加了推送令牌管理和设备注册功能 - 添加了模拟器环境的推送测试用例
这个提交包含在:
父节点
e1925414c9
当前提交
dcbd833e64
1
ops-platform/components.d.ts
vendored
1
ops-platform/components.d.ts
vendored
@ -16,6 +16,7 @@ declare module 'vue' {
|
|||||||
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||||
|
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||||
ElForm: typeof import('element-plus/es')['ElForm']
|
ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||||
|
|||||||
@ -131,6 +131,64 @@ export interface SensitiveWordPage {
|
|||||||
totalPages: number
|
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 = {
|
export const opsApi = {
|
||||||
listTenants: (keyword = '', page = 0, size = 20) =>
|
listTenants: (keyword = '', page = 0, size = 20) =>
|
||||||
client.get<{ data: TenantPage }>('/ops/tenants', { params: { keyword, page, size } }),
|
client.get<{ data: TenantPage }>('/ops/tenants', { params: { keyword, page, size } }),
|
||||||
@ -189,4 +247,13 @@ export const opsApi = {
|
|||||||
|
|
||||||
deleteSensitiveWord: (id: string) =>
|
deleteSensitiveWord: (id: string) =>
|
||||||
client.delete(`/ops/risk/sensitive-words/${id}`),
|
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),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ const router = createRouter({
|
|||||||
{ path: 'service-requests', component: () => import('@/views/services/ServiceRequestsView.vue') },
|
{ path: 'service-requests', component: () => import('@/views/services/ServiceRequestsView.vue') },
|
||||||
{ path: 'apps', component: () => import('@/views/apps/AppListView.vue') },
|
{ path: 'apps', component: () => import('@/views/apps/AppListView.vue') },
|
||||||
{ path: 'apps/:id', component: () => import('@/views/apps/AppDetailView.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: 'operation-logs', component: () => import('@/views/logs/OperationLogView.vue') },
|
||||||
{ path: 'risk-control', component: () => import('@/views/risk/RiskControlView.vue') },
|
{ path: 'risk-control', component: () => import('@/views/risk/RiskControlView.vue') },
|
||||||
],
|
],
|
||||||
|
|||||||
@ -66,7 +66,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { Avatar, Bell, Menu, TrendCharts, Grid, Document, Warning } from '@element-plus/icons-vue'
|
import { Avatar, Bell, Menu, TrendCharts, Grid, Document, Warning, Promotion } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const isMobile = ref(false)
|
const isMobile = ref(false)
|
||||||
@ -77,6 +77,7 @@ const navItems = computed(() => [
|
|||||||
{ path: '/statistics', label: '服务运营总览', icon: TrendCharts },
|
{ path: '/statistics', label: '服务运营总览', icon: TrendCharts },
|
||||||
{ path: '/service-requests', label: '服务开通审核', icon: Bell },
|
{ path: '/service-requests', label: '服务开通审核', icon: Bell },
|
||||||
{ path: '/apps', label: '应用管理', icon: Grid },
|
{ path: '/apps', label: '应用管理', icon: Grid },
|
||||||
|
{ path: '/push', label: 'Push 诊断', icon: Promotion },
|
||||||
{ path: '/operation-logs', label: '操作日志', icon: Document },
|
{ path: '/operation-logs', label: '操作日志', icon: Document },
|
||||||
{ path: '/risk-control', label: '风控配置', icon: Warning },
|
{ path: '/risk-control', label: '风控配置', icon: Warning },
|
||||||
])
|
])
|
||||||
|
|||||||
@ -0,0 +1,256 @@
|
|||||||
|
<template>
|
||||||
|
<div class="push-page">
|
||||||
|
<el-card class="query-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="header-row">
|
||||||
|
<span>Push 诊断</span>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-tag v-if="diagnostics" :type="diagnostics.online ? 'success' : 'info'">
|
||||||
|
{{ diagnostics.online ? '用户在线' : '用户离线' }}
|
||||||
|
</el-tag>
|
||||||
|
<el-button
|
||||||
|
v-if="diagnostics?.appId && diagnostics?.userId"
|
||||||
|
type="primary"
|
||||||
|
:disabled="!diagnostics.deliverableDevices?.length"
|
||||||
|
:loading="testLoading"
|
||||||
|
@click="sendTestOffline"
|
||||||
|
>
|
||||||
|
发送测试离线消息
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-form :model="form" label-width="96px" class="query-form" @submit.prevent="search">
|
||||||
|
<el-form-item label="Token">
|
||||||
|
<el-input
|
||||||
|
v-model="form.token"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="输入 IM token 或厂商 push token"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="AppId">
|
||||||
|
<el-input v-model="form.appId" placeholder="可选;push token 无法解析 AppId 时使用" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :loading="loading" @click="search">查询</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<template v-if="diagnostics">
|
||||||
|
<el-row :gutter="16" class="summary-row">
|
||||||
|
<el-col :xs="24" :md="8">
|
||||||
|
<el-card>
|
||||||
|
<el-statistic title="Token 类型" :value="diagnostics.tokenType" />
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :md="8">
|
||||||
|
<el-card>
|
||||||
|
<el-statistic title="用户" :value="diagnostics.userId || '-'" />
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :md="8">
|
||||||
|
<el-card>
|
||||||
|
<el-statistic title="离线消息" :value="diagnostics.canSendOfflineMessage ? '可送达' : '不可送达'" />
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-card class="section-card">
|
||||||
|
<template #header>当前离线可送达设备</template>
|
||||||
|
<el-empty v-if="!diagnostics.deliverableDevices?.length" description="暂无可送达设备" />
|
||||||
|
<el-table v-else :data="diagnostics.deliverableDevices" border stripe>
|
||||||
|
<el-table-column prop="vendor" label="厂商" width="100" />
|
||||||
|
<el-table-column label="设备" min-width="180">
|
||||||
|
<template #default="{ row }">{{ deviceName(row) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="deviceId" label="DeviceId" min-width="180" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="osVersion" label="系统" width="140" />
|
||||||
|
<el-table-column prop="tokenPreview" label="Token" min-width="170" />
|
||||||
|
<el-table-column label="最近登录" width="180">
|
||||||
|
<template #default="{ row }">{{ fmt(row.lastLoginAt) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card class="section-card">
|
||||||
|
<template #header>当前绑定设备</template>
|
||||||
|
<el-table :data="diagnostics.devices" border stripe>
|
||||||
|
<el-table-column prop="vendor" label="厂商" width="100" />
|
||||||
|
<el-table-column label="设备" min-width="180">
|
||||||
|
<template #default="{ row }">{{ deviceName(row) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="deviceId" label="DeviceId" min-width="180" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="osVersion" label="系统" width="140" />
|
||||||
|
<el-table-column prop="tokenPreview" label="Token" min-width="170" />
|
||||||
|
<el-table-column label="接收 Push" width="110">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.receivePush ? 'success' : 'info'">{{ row.receivePush ? '开启' : '关闭' }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="最近登录" width="180">
|
||||||
|
<template #default="{ row }">{{ fmt(row.lastLoginAt) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card class="section-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="header-row">
|
||||||
|
<span>历史登录设备日志</span>
|
||||||
|
<el-button :disabled="!diagnostics.appId || !diagnostics.userId" :loading="logsLoading" @click="loadLogs">
|
||||||
|
刷新
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table :data="logs" border stripe>
|
||||||
|
<el-table-column prop="eventType" label="事件" width="150" />
|
||||||
|
<el-table-column prop="vendor" label="厂商" width="100" />
|
||||||
|
<el-table-column label="设备" min-width="180">
|
||||||
|
<template #default="{ row }">{{ deviceName(row) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="deviceId" label="DeviceId" min-width="180" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="tokenPreview" label="Token" min-width="170" />
|
||||||
|
<el-table-column label="接收 Push" width="110">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.receivePush ? 'success' : 'info'">{{ row.receivePush ? '开启' : '关闭' }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="时间" width="180">
|
||||||
|
<template #default="{ row }">{{ fmt(row.createdAt) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-pagination
|
||||||
|
class="pager"
|
||||||
|
layout="prev, pager, next, total"
|
||||||
|
:total="logTotal"
|
||||||
|
:page-size="logSize"
|
||||||
|
:current-page="logPage + 1"
|
||||||
|
@current-change="changeLogPage"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { opsApi, type PushDeviceInfo, type PushDeviceLog, type PushDiagnostics } from '@/api/ops'
|
||||||
|
|
||||||
|
const form = reactive({ token: '', appId: '' })
|
||||||
|
const loading = ref(false)
|
||||||
|
const logsLoading = ref(false)
|
||||||
|
const testLoading = ref(false)
|
||||||
|
const diagnostics = ref<PushDiagnostics | null>(null)
|
||||||
|
const logs = ref<PushDeviceLog[]>([])
|
||||||
|
const logTotal = ref(0)
|
||||||
|
const logPage = ref(0)
|
||||||
|
const logSize = 20
|
||||||
|
|
||||||
|
async function search() {
|
||||||
|
if (!form.token.trim()) {
|
||||||
|
ElMessage.warning('请输入 token')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await opsApi.searchPushByToken(form.token.trim(), form.appId.trim())
|
||||||
|
diagnostics.value = res.data.data
|
||||||
|
logs.value = []
|
||||||
|
logTotal.value = 0
|
||||||
|
logPage.value = 0
|
||||||
|
if (diagnostics.value.appId && diagnostics.value.userId) {
|
||||||
|
await loadLogs()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadLogs() {
|
||||||
|
if (!diagnostics.value?.appId || !diagnostics.value?.userId) return
|
||||||
|
logsLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await opsApi.listPushDeviceLogs(
|
||||||
|
diagnostics.value.appId,
|
||||||
|
diagnostics.value.userId,
|
||||||
|
logPage.value,
|
||||||
|
logSize,
|
||||||
|
)
|
||||||
|
logs.value = res.data.data.content
|
||||||
|
logTotal.value = res.data.data.total
|
||||||
|
} finally {
|
||||||
|
logsLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeLogPage(page: number) {
|
||||||
|
logPage.value = page - 1
|
||||||
|
loadLogs()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendTestOffline() {
|
||||||
|
if (!diagnostics.value?.appId || !diagnostics.value?.userId) return
|
||||||
|
testLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await opsApi.sendPushTestOffline({
|
||||||
|
appId: diagnostics.value.appId,
|
||||||
|
userId: diagnostics.value.userId,
|
||||||
|
title: 'XuqmGroup Push 测试',
|
||||||
|
body: `离线推送测试 ${new Date().toLocaleString('zh-CN')}`,
|
||||||
|
payload: JSON.stringify({ type: 'PUSH_TEST', ts: Date.now() }),
|
||||||
|
})
|
||||||
|
ElMessage.success(`已发送到 ${res.data.data.targetCount} 个设备`)
|
||||||
|
} finally {
|
||||||
|
testLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deviceName(device: PushDeviceInfo | PushDeviceLog) {
|
||||||
|
return [device.brand, device.model].filter(Boolean).join(' ') || '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
function fmt(value?: string | number) {
|
||||||
|
if (!value) return '-'
|
||||||
|
return new Date(value).toLocaleString('zh-CN')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.push-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.query-card,
|
||||||
|
.section-card {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.header-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.query-form {
|
||||||
|
max-width: 920px;
|
||||||
|
}
|
||||||
|
.summary-row {
|
||||||
|
row-gap: 16px;
|
||||||
|
}
|
||||||
|
.pager {
|
||||||
|
margin-top: 16px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -116,7 +116,7 @@ export const appApi = {
|
|||||||
appId: string,
|
appId: string,
|
||||||
platform: string,
|
platform: string,
|
||||||
serviceType: string,
|
serviceType: string,
|
||||||
config: Partial<ImServiceConfig> & Partial<UpdateServiceConfig> & Partial<PushServiceConfig>,
|
config: Partial<ImServiceConfig> & Partial<UpdateServiceConfig> & Partial<PushServiceConfig> | Record<string, unknown>,
|
||||||
) =>
|
) =>
|
||||||
client.put<{ data: FeatureService }>(`/apps/${appId}/services/config`, config, {
|
client.put<{ data: FeatureService }>(`/apps/${appId}/services/config`, config, {
|
||||||
params: { platform, serviceType },
|
params: { platform, serviceType },
|
||||||
|
|||||||
@ -50,8 +50,7 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-else
|
v-else
|
||||||
v-model="pushConfig[vendor.key][field.key]"
|
v-model="pushConfig[vendor.key][field.key]"
|
||||||
:type="field.type === 'password' ? 'password' : 'text'"
|
type="text"
|
||||||
:show-password="field.type === 'password'"
|
|
||||||
:placeholder="field.placeholder"
|
:placeholder="field.placeholder"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -78,7 +77,7 @@ type VendorKey = keyof PushServiceConfig
|
|||||||
type FieldDef = {
|
type FieldDef = {
|
||||||
key: string
|
key: string
|
||||||
label: string
|
label: string
|
||||||
type?: 'password' | 'textarea' | 'switch'
|
type?: 'textarea' | 'switch'
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
rows?: number
|
rows?: number
|
||||||
}
|
}
|
||||||
@ -117,7 +116,7 @@ const vendorDefs: VendorDef[] = [
|
|||||||
hint: '填写 AppId / AppSecret,供服务端推送使用。',
|
hint: '填写 AppId / AppSecret,供服务端推送使用。',
|
||||||
fields: [
|
fields: [
|
||||||
{ key: 'appId', label: 'AppId' },
|
{ key: 'appId', label: 'AppId' },
|
||||||
{ key: 'appSecret', label: 'AppSecret', type: 'password' },
|
{ key: 'appSecret', label: 'AppSecret' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -127,7 +126,7 @@ const vendorDefs: VendorDef[] = [
|
|||||||
fields: [
|
fields: [
|
||||||
{ key: 'appId', label: 'AppId' },
|
{ key: 'appId', label: 'AppId' },
|
||||||
{ key: 'appKey', label: 'AppKey' },
|
{ key: 'appKey', label: 'AppKey' },
|
||||||
{ key: 'appSecret', label: 'AppSecret', type: 'password' },
|
{ key: 'appSecret', label: 'AppSecret' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -137,7 +136,7 @@ const vendorDefs: VendorDef[] = [
|
|||||||
fields: [
|
fields: [
|
||||||
{ key: 'appId', label: 'AppId' },
|
{ key: 'appId', label: 'AppId' },
|
||||||
{ key: 'appKey', label: 'AppKey' },
|
{ key: 'appKey', label: 'AppKey' },
|
||||||
{ key: 'masterSecret', label: 'MasterSecret', type: 'password' },
|
{ key: 'masterSecret', label: 'MasterSecret' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -147,7 +146,7 @@ const vendorDefs: VendorDef[] = [
|
|||||||
fields: [
|
fields: [
|
||||||
{ key: 'appId', label: 'AppId' },
|
{ key: 'appId', label: 'AppId' },
|
||||||
{ key: 'appKey', label: 'AppKey' },
|
{ key: 'appKey', label: 'AppKey' },
|
||||||
{ key: 'appSecret', label: 'AppSecret', type: 'password' },
|
{ key: 'appSecret', label: 'AppSecret' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -157,7 +156,7 @@ const vendorDefs: VendorDef[] = [
|
|||||||
fields: [
|
fields: [
|
||||||
{ key: 'appId', label: 'AppId' },
|
{ key: 'appId', label: 'AppId' },
|
||||||
{ key: 'clientId', label: 'ClientId' },
|
{ 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
|
if (!app.value) return
|
||||||
saving.value = true
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
await appApi.updateServiceConfig(app.value.id, servicePlatform.value, 'PUSH', pushConfig)
|
await appApi.updateServiceConfig(app.value.id, servicePlatform.value, 'PUSH', toPushConfigRequest())
|
||||||
ElMessage.success('推送配置已保存')
|
ElMessage.success('推送配置已保存')
|
||||||
await loadData()
|
await loadData()
|
||||||
} catch {
|
} catch {
|
||||||
@ -222,6 +221,31 @@ async function saveConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toPushConfigRequest(): Record<string, string | boolean> {
|
||||||
|
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) {
|
async function onTogglePushService(enable: boolean) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
ElMessage.info('请通过服务开通流程启用推送服务')
|
ElMessage.info('请通过服务开通流程启用推送服务')
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户