feat(push): 测试推送支持选择指定设备,默认最近登录设备

- 设备选择器显示全部设备,预选最近登录项
- sent=false && targetCount>0 时显示厂商拒绝提示
- testOffline API 新增 deviceId 参数

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-26 13:21:36 +08:00
父节点 dc1ed28532
当前提交 68a56a3575
共有 2 个文件被更改,包括 23 次插入4 次删除

查看文件

@ -81,10 +81,11 @@ export const pushAdminApi = {
})
},
testOffline(appKey: string, userId: string, title: string, body: string, payload?: string) {
testOffline(appKey: string, userId: string, title: string, body: string, payload?: string, deviceId?: string | null) {
return client.post<{ data: TestPushResult }>('/push/admin/test-offline', {
appKey,
userId,
deviceId: deviceId ?? null,
title,
body,
payload: payload ?? null,

查看文件

@ -106,6 +106,17 @@
<el-card shadow="never" style="margin-bottom:0">
<template #header>发送测试离线推送</template>
<el-form :model="testForm" label-width="90px" style="max-width:560px">
<el-form-item label="目标设备">
<el-select v-model="testForm.deviceId" style="width:100%" placeholder="按策略自动选择">
<el-option :value="null" label="按策略自动推送(平台按登录模式选取)" />
<el-option
v-for="dev in userStatus?.devices"
:key="dev.id"
:value="dev.id"
:label="`${dev.vendor}${dev.brand ? ' · ' + dev.brand : ''}${dev.model ? ' ' + dev.model : ''}${dev.lastLoginAt ? ' · 登录 ' + formatTime(dev.lastLoginAt) : ''}${!dev.receivePush ? ' [已关闭推送]' : ''}`"
/>
</el-select>
</el-form-item>
<el-form-item label="标题">
<el-input v-model="testForm.title" placeholder="推送标题" />
</el-form-item>
@ -126,8 +137,12 @@
</el-form>
<template v-if="testResult">
<el-alert
:title="testResult.sent ? `推送已发出,目标设备 ${testResult.targetCount} 台` : '无可用推送目标,未发送'"
:type="testResult.sent ? 'success' : 'warning'"
:title="testResult.sent
? `推送已发出,目标设备 ${testResult.targetCount}`
: testResult.targetCount > 0
? '设备已找到但推送失败,请检查厂商凭据配置(小米 AppSecret / VIVO AppKey 等)'
: '无可用推送目标,未发送'"
:type="testResult.sent ? 'success' : testResult.targetCount > 0 ? 'error' : 'warning'"
:closable="false"
show-icon
style="margin-top:12px"
@ -246,7 +261,7 @@ const queryUserId = ref('')
const querying = ref(false)
const userStatus = ref<UserPushStatus | null>(null)
const testForm = reactive({ title: '', body: '', payload: '' })
const testForm = reactive({ title: '', body: '', payload: '', deviceId: null as string | null })
const sending = ref(false)
const testResult = ref<TestPushResult | null>(null)
@ -274,6 +289,8 @@ async function queryUser() {
try {
const res = await pushAdminApi.getUserStatus(appKey.value, uid)
userStatus.value = res.data.data
// default to last-login device (devices are ordered by lastLoginAt DESC)
testForm.deviceId = res.data.data.devices[0]?.id ?? null
logsUserId.value = uid
logsPage.value = 1
await loadLogs()
@ -295,6 +312,7 @@ async function sendTestPush() {
testForm.title,
testForm.body,
testForm.payload || undefined,
testForm.deviceId,
)
testResult.value = res.data.data
} catch {