2026-05-05 23:18:02 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div>
|
2026-05-07 13:53:02 +08:00
|
|
|
|
<div v-if="isServicesPortal" class="portal-bar">
|
|
|
|
|
|
<span class="portal-bar-title">离线推送管理</span>
|
2026-05-07 19:39:47 +08:00
|
|
|
|
<el-select :model-value="appKey" placeholder="选择应用" style="width:220px" @change="switchApp">
|
2026-05-07 13:53:02 +08:00
|
|
|
|
<el-option v-for="a in portalApps" :key="a.appKey" :label="a.name" :value="a.appKey" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-page-header v-else @back="$router.back()" content="推送管理" style="margin-bottom:24px" />
|
2026-05-07 19:39:47 +08:00
|
|
|
|
<el-empty v-if="isServicesPortal && !appKey" description="请选择一个应用" style="margin-top:80px" />
|
2026-05-05 23:18:02 +08:00
|
|
|
|
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
<div v-if="isServicesPortal && appKey && checkingService" v-loading="true" style="min-height:200px" />
|
|
|
|
|
|
|
|
|
|
|
|
<template v-if="isServicesPortal && appKey && serviceEnabled === false">
|
|
|
|
|
|
<el-empty :image-size="80" description="当前应用未开通离线推送服务" style="margin-top:60px">
|
|
|
|
|
|
<el-button type="primary" @click="showActivationDialog = true">申请开通</el-button>
|
|
|
|
|
|
</el-empty>
|
|
|
|
|
|
<el-dialog v-model="showActivationDialog" title="申请开通离线推送" width="460px">
|
|
|
|
|
|
<el-form label-width="80px">
|
|
|
|
|
|
<el-form-item label="服务">离线推送</el-form-item>
|
|
|
|
|
|
<el-form-item label="申请理由">
|
|
|
|
|
|
<el-input v-model="activationReason" type="textarea" :rows="3" placeholder="请描述您的业务场景" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<el-button @click="showActivationDialog = false">取消</el-button>
|
|
|
|
|
|
<el-button type="primary" :loading="submittingActivation" @click="submitActivation">提交申请</el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<template v-if="!isServicesPortal || (appKey && serviceEnabled === true)">
|
2026-05-05 23:18:02 +08:00
|
|
|
|
<el-card style="margin-bottom:16px">
|
|
|
|
|
|
<template #header>用户设备状态查询</template>
|
|
|
|
|
|
<el-form inline @submit.prevent="queryUser">
|
|
|
|
|
|
<el-form-item label="用户 ID">
|
|
|
|
|
|
<el-input v-model="queryUserId" placeholder="请输入用户 ID" clearable style="width:240px" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item>
|
|
|
|
|
|
<el-button type="primary" :loading="querying" @click="queryUser">查询</el-button>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
|
|
|
|
|
<template v-if="userStatus">
|
|
|
|
|
|
<el-divider />
|
|
|
|
|
|
<el-descriptions :column="isMobile ? 1 : 3" border size="small" style="margin-bottom:16px">
|
|
|
|
|
|
<el-descriptions-item label="用户 ID">{{ userStatus.userId }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="在线状态">
|
|
|
|
|
|
<el-tag :type="userStatus.online ? 'success' : 'info'">
|
|
|
|
|
|
{{ userStatus.online ? '在线' : '离线' }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="最后在线">
|
|
|
|
|
|
{{ userStatus.lastSeenAt ? formatTime(userStatus.lastSeenAt) : '-' }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="可推送设备数">
|
|
|
|
|
|
{{ userStatus.deliverableDevices.length }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="离线可达">
|
|
|
|
|
|
<el-tag :type="userStatus.canSendOfflineMessage ? 'success' : 'warning'">
|
|
|
|
|
|
{{ userStatus.canSendOfflineMessage ? '可发送' : '不可发送' }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="注册设备总数">{{ userStatus.devices.length }}</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table :data="userStatus.devices" border size="small" style="margin-bottom:16px">
|
|
|
|
|
|
<el-table-column label="厂商" width="90">
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
<el-tag size="small" effect="plain">{{ row.vendor }}</el-tag>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="平台" prop="platform" width="90" />
|
|
|
|
|
|
<el-table-column label="品牌" prop="brand" width="80" />
|
|
|
|
|
|
<el-table-column label="型号" prop="model" min-width="110" />
|
|
|
|
|
|
<el-table-column label="系统版本" prop="osVersion" width="100" />
|
|
|
|
|
|
<el-table-column label="App 版本" prop="appVersion" width="90" />
|
|
|
|
|
|
<el-table-column label="Token 预览" prop="tokenPreview" min-width="140" />
|
|
|
|
|
|
<el-table-column label="接收推送" width="90" align="center">
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
<el-tag :type="row.receivePush ? 'success' : 'danger'" size="small">
|
|
|
|
|
|
{{ row.receivePush ? '是' : '否' }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="最后登录" min-width="160">
|
2026-05-07 13:53:02 +08:00
|
|
|
|
<template #default="{ row }">{{ row.lastLoginAt ? formatDateTime(row.lastLoginAt) : '-' }}</template>
|
2026-05-05 23:18:02 +08:00
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
<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-input v-model="testForm.title" placeholder="推送标题" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="内容">
|
|
|
|
|
|
<el-input v-model="testForm.body" placeholder="推送内容" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="Payload">
|
|
|
|
|
|
<el-input v-model="testForm.payload" placeholder="自定义 JSON payload(可选)" type="textarea" :rows="2" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
:disabled="!testForm.title || !testForm.body"
|
|
|
|
|
|
:loading="sending"
|
|
|
|
|
|
@click="sendTestPush"
|
|
|
|
|
|
>发送</el-button>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<template v-if="testResult">
|
|
|
|
|
|
<el-alert
|
|
|
|
|
|
:title="testResult.sent ? `推送已发出,目标设备 ${testResult.targetCount} 台` : '无可用推送目标,未发送'"
|
|
|
|
|
|
:type="testResult.sent ? 'success' : 'warning'"
|
|
|
|
|
|
:closable="false"
|
|
|
|
|
|
show-icon
|
|
|
|
|
|
style="margin-top:12px"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<el-card>
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<span>设备登录日志</span>
|
|
|
|
|
|
<span v-if="logsUserId" style="font-size:12px;color:#909399;margin-left:8px">
|
|
|
|
|
|
用户:{{ logsUserId }}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<el-form inline style="margin-bottom:12px" @submit.prevent="loadLogs">
|
|
|
|
|
|
<el-form-item label="用户 ID">
|
|
|
|
|
|
<el-input v-model="logsUserId" placeholder="请输入用户 ID" clearable style="width:240px" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item>
|
|
|
|
|
|
<el-button type="primary" :loading="logsLoading" @click="loadLogs">查询日志</el-button>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table :data="logs" border size="small" v-loading="logsLoading">
|
|
|
|
|
|
<el-table-column label="厂商" width="90">
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
<el-tag size="small" effect="plain">{{ row.vendor }}</el-tag>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="平台" prop="platform" width="90" />
|
|
|
|
|
|
<el-table-column label="品牌" prop="brand" width="80" />
|
|
|
|
|
|
<el-table-column label="型号" prop="model" min-width="110" />
|
|
|
|
|
|
<el-table-column label="系统版本" prop="osVersion" width="100" />
|
|
|
|
|
|
<el-table-column label="App 版本" prop="appVersion" width="90" />
|
|
|
|
|
|
<el-table-column label="设备 ID" prop="deviceId" min-width="140" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column label="登录时间" prop="createdAt" min-width="160" />
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="logsTotalPages > 1" style="margin-top:12px;display:flex;justify-content:flex-end">
|
|
|
|
|
|
<el-pagination
|
|
|
|
|
|
v-model:current-page="logsPage"
|
|
|
|
|
|
:page-size="logsPageSize"
|
|
|
|
|
|
:total="logsTotal"
|
|
|
|
|
|
layout="prev, pager, next"
|
|
|
|
|
|
@current-change="loadLogs"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
2026-05-07 13:53:02 +08:00
|
|
|
|
</template>
|
2026-05-05 23:18:02 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
2026-05-07 13:53:02 +08:00
|
|
|
|
import { useRoute, useRouter } from 'vue-router'
|
2026-05-05 23:18:02 +08:00
|
|
|
|
import { ElMessage } from 'element-plus'
|
2026-05-07 13:53:02 +08:00
|
|
|
|
import { appApi, type App } from '@/api/app'
|
2026-05-05 23:18:02 +08:00
|
|
|
|
import { pushAdminApi, type DeviceLoginLog, type TestPushResult, type UserPushStatus } from '@/api/push'
|
2026-05-16 14:27:02 +08:00
|
|
|
|
import {
|
|
|
|
|
|
connectServiceActivationRealtime,
|
|
|
|
|
|
disconnectServiceActivationRealtime,
|
|
|
|
|
|
type ServiceActivationRefreshEvent,
|
|
|
|
|
|
} from '@/services/storeReviewRealtime'
|
2026-05-05 23:18:02 +08:00
|
|
|
|
|
|
|
|
|
|
const route = useRoute()
|
2026-05-07 13:53:02 +08:00
|
|
|
|
const router = useRouter()
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
const appKey = computed(() => (route.params.appKey as string) ?? '')
|
2026-05-07 13:53:02 +08:00
|
|
|
|
const isServicesPortal = computed(() => route.path.startsWith('/services/'))
|
|
|
|
|
|
const portalApps = ref<App[]>([])
|
2026-05-05 23:18:02 +08:00
|
|
|
|
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
const serviceEnabled = ref<boolean | null>(null)
|
|
|
|
|
|
const checkingService = ref(false)
|
|
|
|
|
|
const showActivationDialog = ref(false)
|
|
|
|
|
|
const activationReason = ref('')
|
|
|
|
|
|
const submittingActivation = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
async function checkServiceEnabled() {
|
|
|
|
|
|
checkingService.value = true
|
|
|
|
|
|
serviceEnabled.value = null
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await appApi.getServices(appKey.value)
|
|
|
|
|
|
serviceEnabled.value = res.data.data.some(s => s.serviceType === 'PUSH' && s.enabled)
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
serviceEnabled.value = false
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
checkingService.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function submitActivation() {
|
|
|
|
|
|
if (!activationReason.value.trim()) {
|
|
|
|
|
|
ElMessage.warning('请填写申请理由')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
submittingActivation.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
await appApi.requestActivation(appKey.value, 'PUSH', activationReason.value.trim())
|
|
|
|
|
|
ElMessage.success('申请已提交,等待运营审核')
|
|
|
|
|
|
showActivationDialog.value = false
|
|
|
|
|
|
activationReason.value = ''
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
ElMessage.error('提交失败')
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
submittingActivation.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-05 23:18:02 +08:00
|
|
|
|
const isMobile = ref(window.innerWidth < 768)
|
|
|
|
|
|
function updateViewport() { isMobile.value = window.innerWidth < 768 }
|
|
|
|
|
|
|
|
|
|
|
|
const queryUserId = ref('')
|
|
|
|
|
|
const querying = ref(false)
|
|
|
|
|
|
const userStatus = ref<UserPushStatus | null>(null)
|
|
|
|
|
|
|
|
|
|
|
|
const testForm = reactive({ title: '', body: '', payload: '' })
|
|
|
|
|
|
const sending = ref(false)
|
|
|
|
|
|
const testResult = ref<TestPushResult | null>(null)
|
|
|
|
|
|
|
|
|
|
|
|
const logsUserId = ref('')
|
|
|
|
|
|
const logsLoading = ref(false)
|
|
|
|
|
|
const logs = ref<DeviceLoginLog[]>([])
|
|
|
|
|
|
const logsPage = ref(1)
|
|
|
|
|
|
const logsPageSize = 20
|
|
|
|
|
|
const logsTotal = ref(0)
|
|
|
|
|
|
const logsTotalPages = ref(0)
|
|
|
|
|
|
|
2026-05-07 13:53:02 +08:00
|
|
|
|
function switchApp(val: string) {
|
|
|
|
|
|
router.push(`/services/push/${val}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-05 23:18:02 +08:00
|
|
|
|
async function queryUser() {
|
|
|
|
|
|
const uid = queryUserId.value.trim()
|
|
|
|
|
|
if (!uid) {
|
|
|
|
|
|
ElMessage.warning('请输入用户 ID')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
querying.value = true
|
|
|
|
|
|
testResult.value = null
|
|
|
|
|
|
try {
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
const res = await pushAdminApi.getUserStatus(appKey.value, uid)
|
2026-05-05 23:18:02 +08:00
|
|
|
|
userStatus.value = res.data.data
|
|
|
|
|
|
logsUserId.value = uid
|
|
|
|
|
|
logsPage.value = 1
|
|
|
|
|
|
await loadLogs()
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
userStatus.value = null
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
querying.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function sendTestPush() {
|
|
|
|
|
|
if (!userStatus.value) return
|
|
|
|
|
|
sending.value = true
|
|
|
|
|
|
testResult.value = null
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await pushAdminApi.testOffline(
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
appKey.value,
|
2026-05-05 23:18:02 +08:00
|
|
|
|
userStatus.value.userId,
|
|
|
|
|
|
testForm.title,
|
|
|
|
|
|
testForm.body,
|
|
|
|
|
|
testForm.payload || undefined,
|
|
|
|
|
|
)
|
|
|
|
|
|
testResult.value = res.data.data
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
// error shown by client interceptor
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
sending.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function loadLogs() {
|
|
|
|
|
|
const uid = logsUserId.value.trim()
|
|
|
|
|
|
if (!uid) return
|
|
|
|
|
|
logsLoading.value = true
|
|
|
|
|
|
try {
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
const res = await pushAdminApi.getDeviceLogs(appKey.value, uid, logsPage.value - 1, logsPageSize)
|
2026-05-05 23:18:02 +08:00
|
|
|
|
const d = res.data.data
|
|
|
|
|
|
logs.value = d.content
|
|
|
|
|
|
logsTotal.value = d.total
|
|
|
|
|
|
logsTotalPages.value = d.totalPages
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
logs.value = []
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
logsLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function formatTime(ms: number): string {
|
|
|
|
|
|
if (!ms) return '-'
|
|
|
|
|
|
return new Date(ms).toLocaleString('zh-CN')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-07 13:53:02 +08:00
|
|
|
|
function formatDateTime(iso: string): string {
|
|
|
|
|
|
if (!iso) return '-'
|
|
|
|
|
|
return new Date(iso).toLocaleString('zh-CN')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-16 14:27:02 +08:00
|
|
|
|
function connectPushRealtime(key: string) {
|
|
|
|
|
|
void connectServiceActivationRealtime(key, (event: ServiceActivationRefreshEvent) => {
|
|
|
|
|
|
if (event.serviceType !== 'PUSH') return
|
|
|
|
|
|
if (event.status === 'APPROVED') {
|
|
|
|
|
|
ElMessage.success('离线推送服务已审核通过')
|
|
|
|
|
|
checkServiceEnabled()
|
|
|
|
|
|
} else if (event.status === 'REJECTED') {
|
|
|
|
|
|
ElMessage.error(`离线推送服务审核未通过:${event.reviewNote || '请联系运营'}`)
|
|
|
|
|
|
checkServiceEnabled()
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
watch(appKey, (key) => {
|
|
|
|
|
|
if (isServicesPortal.value && key) checkServiceEnabled()
|
2026-05-16 14:27:02 +08:00
|
|
|
|
if (key) connectPushRealtime(key)
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
2026-05-07 13:53:02 +08:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
if (isServicesPortal.value) {
|
|
|
|
|
|
appApi.list().then(res => { portalApps.value = res.data.data })
|
docs: fix version numbers, add license SDK docs; fix service gating reactivity
- Android: correct version header 0.5.x→0.4.x, add sdk-license to module table, update artifact versions to 0.4.10
- iOS: correct min version iOS 14→16, bump version to 0.2.0, update SPM ref to from: "0.2.0"
- RN: fix version 0.3.x→0.2.x, standardize npm registry URL, add @xuqm/rn-license to module table
- Flutter: update git ref to v0.2.2, add xuqm_flutter_license to module tables
- Add new docs: ios/license, rn/push, rn/license, flutter/push, flutter/update, flutter/license
- tenant-platform: make appKey a computed ref in Push/VersionManagementView to fix service gating reactivity on route change
- tenant-platform: add requestActivation API endpoint
- tenant-platform: add IM service gating UI (checkServiceEnabled + activation dialog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 02:23:57 +08:00
|
|
|
|
if (appKey.value) {
|
|
|
|
|
|
checkServiceEnabled()
|
|
|
|
|
|
}
|
2026-05-07 13:53:02 +08:00
|
|
|
|
}
|
2026-05-16 14:27:02 +08:00
|
|
|
|
if (appKey.value) connectPushRealtime(appKey.value)
|
2026-05-07 13:53:02 +08:00
|
|
|
|
window.addEventListener('resize', updateViewport)
|
|
|
|
|
|
})
|
2026-05-16 14:27:02 +08:00
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
|
window.removeEventListener('resize', updateViewport)
|
|
|
|
|
|
disconnectServiceActivationRealtime()
|
|
|
|
|
|
})
|
2026-05-05 23:18:02 +08:00
|
|
|
|
</script>
|
2026-05-07 13:53:02 +08:00
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.portal-bar {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
margin-bottom: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.portal-bar-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|