From 0f57fe3b7186dc3777b7c7cbcf64f0e39f14aded Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Tue, 5 May 2026 22:26:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(push):=20=E6=B7=BB=E5=8A=A0=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E6=9C=8D=E5=8A=A1=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增推送相关的类型定义,包括消息类型、聊天类型、推送配置等接口 - 实现 HarmonyOS 推送 SDK,集成 HarmonyOS NEXT Push Kit 服务 - 实现 iOS 推送 SDK,支持 APNS 推送注册和消息接收 - 添加服务器端 APNS 推送提供商,支持 JWT 认证和推送消息发送 - 添加服务器端 HarmonyOS 推送提供商基础框架 - 集成推送配置加载和路由功能,支持多渠道推送分类管理 --- tenant-platform/components.d.ts | 1 + tenant-platform/src/api/app.ts | 1 + .../src/views/push/PushConfigView.vue | 54 +++++++++++++++++-- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/tenant-platform/components.d.ts b/tenant-platform/components.d.ts index ae4117b..237a0de 100644 --- a/tenant-platform/components.d.ts +++ b/tenant-platform/components.d.ts @@ -46,6 +46,7 @@ declare module 'vue' { ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] + ElSegmented: typeof import('element-plus/es')['ElSegmented'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElSlider: typeof import('element-plus/es')['ElSlider'] ElSpace: typeof import('element-plus/es')['ElSpace'] diff --git a/tenant-platform/src/api/app.ts b/tenant-platform/src/api/app.ts index a2d579e..34de9ff 100644 --- a/tenant-platform/src/api/app.ts +++ b/tenant-platform/src/api/app.ts @@ -77,6 +77,7 @@ export interface PushServiceConfig { oppo?: PushVendorConfig vivo?: PushVendorConfig honor?: PushVendorConfig + harmony?: PushVendorConfig apns?: PushVendorConfig fcm?: PushVendorConfig channels?: PushNotificationChannelConfig[] diff --git a/tenant-platform/src/views/push/PushConfigView.vue b/tenant-platform/src/views/push/PushConfigView.vue index 6f6229e..9cb1c4e 100644 --- a/tenant-platform/src/views/push/PushConfigView.vue +++ b/tenant-platform/src/views/push/PushConfigView.vue @@ -13,6 +13,9 @@ {{ pushEnabled ? '已开通' : '未开通' }} + + +
@@ -176,6 +179,12 @@ const services = ref([]) const loading = ref(false) const saving = ref(false) const isMobile = ref(window.innerWidth < 768) +const selectedPlatform = ref<'ANDROID' | 'IOS' | 'HARMONY'>('ANDROID') +const platformOptions = [ + { label: 'Android', value: 'ANDROID' }, + { label: 'iOS', value: 'IOS' }, + { label: '鸿蒙', value: 'HARMONY' }, +] function updateViewport() { isMobile.value = window.innerWidth < 768 @@ -187,6 +196,7 @@ const pushConfig = reactive>({ oppo: { appId: '', appKey: '', masterSecret: '' }, vivo: { appId: '', appKey: '', appSecret: '' }, honor: { appId: '', clientId: '', clientSecret: '' }, + harmony: { appId: '', appSecret: '' }, apns: { teamId: '', keyId: '', bundleId: '', keyPath: '', sandbox: false }, fcm: { serviceAccountJson: '' }, channels: defaultChannels(), @@ -263,6 +273,15 @@ const vendorDefs: VendorDef[] = [ { key: 'clientSecret', label: 'ClientSecret' }, ], }, + { + key: 'harmony', + label: '鸿蒙 Push Kit', + hint: '填写 HarmonyOS Push Kit AppId / AppSecret。', + fields: [ + { key: 'appId', label: 'AppId' }, + { key: 'appSecret', label: 'AppSecret' }, + ], + }, { key: 'apns', label: 'APNs(iOS)', @@ -277,8 +296,10 @@ const vendorDefs: VendorDef[] = [ }, ] -const pushEnabled = computed(() => services.value.some(s => s.serviceType === 'PUSH' && s.enabled)) -const servicePlatform = computed(() => services.value.find(s => s.serviceType === 'PUSH')?.platform ?? 'ANDROID') +const pushEnabled = computed(() => services.value.some( + s => s.serviceType === 'PUSH' && s.platform === selectedPlatform.value && s.enabled, +)) +const servicePlatform = computed(() => selectedPlatform.value) async function loadData() { const id = route.params.appId as string @@ -288,16 +309,28 @@ async function loadData() { ]) app.value = appRes.data.data services.value = svcRes.data.data - applyConfig(services.value.find(s => s.serviceType === 'PUSH')?.config) + const firstPushService = services.value.find(s => s.serviceType === 'PUSH') + if (firstPushService && !services.value.some(s => s.serviceType === 'PUSH' && s.platform === selectedPlatform.value)) { + selectedPlatform.value = firstPushService.platform + } + applySelectedPlatformConfig() +} + +function applySelectedPlatformConfig() { + applyConfig(services.value.find( + s => s.serviceType === 'PUSH' && s.platform === selectedPlatform.value, + )?.config) } function applyConfig(raw?: string | null) { + resetPushConfig() const parsed = parseConfig(raw) pushConfig.huawei = { ...pushConfig.huawei, ...parsed.huawei } pushConfig.xiaomi = { ...pushConfig.xiaomi, ...parsed.xiaomi } pushConfig.oppo = { ...pushConfig.oppo, ...parsed.oppo } pushConfig.vivo = { ...pushConfig.vivo, ...parsed.vivo } pushConfig.honor = { ...pushConfig.honor, ...parsed.honor } + pushConfig.harmony = { ...pushConfig.harmony, ...parsed.harmony } pushConfig.apns = { ...pushConfig.apns, ...parsed.apns } pushConfig.fcm = { ...pushConfig.fcm, ...parsed.fcm } pushConfig.channels = normalizeChannels(parsed.channels) @@ -305,6 +338,19 @@ function applyConfig(raw?: string | null) { originalChannels.value = pushConfig.channels.map(channel => ({ ...channel })) } +function resetPushConfig() { + pushConfig.huawei = { appId: '', appSecret: '' } + pushConfig.xiaomi = { appId: '', appKey: '', appSecret: '' } + pushConfig.oppo = { appId: '', appKey: '', masterSecret: '' } + pushConfig.vivo = { appId: '', appKey: '', appSecret: '' } + pushConfig.honor = { appId: '', clientId: '', clientSecret: '' } + pushConfig.harmony = { appId: '', appSecret: '' } + pushConfig.apns = { teamId: '', keyId: '', bundleId: '', keyPath: '', sandbox: false } + pushConfig.fcm = { serviceAccountJson: '' } + pushConfig.channels = defaultChannels() + pushConfig.routing = defaultRouting() +} + function parseConfig(raw?: string | null): PushServiceConfig { if (!raw) return {} try { @@ -345,6 +391,8 @@ function toPushConfigRequest(): Record { honorAppId: pushConfig.honor.appId ?? '', honorClientId: pushConfig.honor.clientId ?? '', honorClientSecret: pushConfig.honor.clientSecret ?? '', + harmonyAppId: pushConfig.harmony.appId ?? '', + harmonyAppSecret: pushConfig.harmony.appSecret ?? '', apnsTeamId: pushConfig.apns.teamId ?? '', apnsKeyId: pushConfig.apns.keyId ?? '', apnsBundleId: pushConfig.apns.bundleId ?? '',