增加xpush
This commit is contained in:
@@ -60,6 +60,7 @@ export type {
|
||||
AdminAgisoMessagingDefaults,
|
||||
AdminAgisoObservedShopItem,
|
||||
AdminNotificationBarkRecipient,
|
||||
AdminNotificationWpushRecipient,
|
||||
AdminNotificationConfig,
|
||||
AdminNotificationSendResult,
|
||||
AdminNotificationTestResult,
|
||||
|
||||
@@ -6,6 +6,7 @@ export type {
|
||||
|
||||
export type {
|
||||
AdminNotificationBarkRecipient,
|
||||
AdminNotificationWpushRecipient,
|
||||
AdminNotificationConfig,
|
||||
AdminNotificationSendResult,
|
||||
AdminNotificationTestResult,
|
||||
|
||||
@@ -6,6 +6,14 @@ export interface AdminNotificationBarkRecipient {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export interface AdminNotificationWpushRecipient {
|
||||
id: string
|
||||
name: string
|
||||
apiKey: string
|
||||
apiKeyMasked: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export interface AdminNotificationConfig {
|
||||
enabled: boolean
|
||||
channels: {
|
||||
@@ -14,10 +22,15 @@ export interface AdminNotificationConfig {
|
||||
serverUrl: string
|
||||
recipients: AdminNotificationBarkRecipient[]
|
||||
}
|
||||
wpush: {
|
||||
enabled: boolean
|
||||
recipients: AdminNotificationWpushRecipient[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface AdminNotificationSendResult {
|
||||
channel: string
|
||||
recipientId: string
|
||||
recipientName: string
|
||||
recipientKeyMasked: string
|
||||
|
||||
@@ -64,6 +64,7 @@ const {
|
||||
notificationFilePath,
|
||||
notificationForm,
|
||||
notificationRecipients,
|
||||
wpushRecipients,
|
||||
notificationSaving,
|
||||
notificationTesting,
|
||||
notificationResultError,
|
||||
@@ -263,10 +264,12 @@ onMounted(loadConfigs)
|
||||
{
|
||||
key: 'notifications',
|
||||
label: '内部通知',
|
||||
tag: 'Bark / 值班',
|
||||
value: notificationStats.enabledRecipientCount,
|
||||
tag: 'Bark / WPush',
|
||||
value:
|
||||
notificationStats.barkEnabledRecipientCount +
|
||||
notificationStats.wpushEnabledRecipientCount,
|
||||
unit: '启用接收人',
|
||||
meta: `配置 ${notificationStats.configuredRecipientCount} 人 · 最近成功 ${notificationStats.lastSuccessCount} 个`,
|
||||
meta: `Bark ${notificationStats.barkConfiguredRecipientCount} 人 · WPush ${notificationStats.wpushConfiguredRecipientCount} 人 · 最近成功 ${notificationStats.lastSuccessCount} 个`,
|
||||
},
|
||||
{
|
||||
key: 'ninetyone',
|
||||
@@ -356,6 +359,7 @@ onMounted(loadConfigs)
|
||||
:notification-file-path="notificationFilePath"
|
||||
:notification-form="notificationForm"
|
||||
:notification-recipients="notificationRecipients"
|
||||
:wpush-recipients="wpushRecipients"
|
||||
:notification-saving="notificationSaving"
|
||||
:notification-testing="notificationTesting"
|
||||
:notification-result-error="notificationResultError"
|
||||
|
||||
+9
-4
@@ -5,15 +5,20 @@ type NotificationForm = {
|
||||
enabled: boolean
|
||||
barkEnabled: boolean
|
||||
barkServerUrl: string
|
||||
wpushEnabled: boolean
|
||||
testTitle: string
|
||||
testBody: string
|
||||
testUrl: string
|
||||
}
|
||||
|
||||
type NotificationStats = {
|
||||
configuredRecipientCount: number
|
||||
enabledRecipientCount: number
|
||||
barkConfiguredRecipientCount: number
|
||||
barkEnabledRecipientCount: number
|
||||
wpushConfiguredRecipientCount: number
|
||||
wpushEnabledRecipientCount: number
|
||||
barkReady: boolean
|
||||
wpushReady: boolean
|
||||
ready: boolean
|
||||
lastSuccessCount: number
|
||||
lastFailedCount: number
|
||||
scheduledJobEnabledCount: number
|
||||
@@ -40,8 +45,8 @@ defineProps<Props>()
|
||||
<div>
|
||||
<span class="card-title">Bark 通知</span>
|
||||
<p class="card-desc">
|
||||
已配置 {{ notificationStats.configuredRecipientCount }} 人,启用
|
||||
{{ notificationStats.enabledRecipientCount }} 人。
|
||||
已配置 {{ notificationStats.barkConfiguredRecipientCount }} 人,启用
|
||||
{{ notificationStats.barkEnabledRecipientCount }} 人。
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
|
||||
+3
@@ -16,6 +16,9 @@ defineProps<Props>()
|
||||
<el-descriptions-item label="职责"
|
||||
>内部运营通知,仅发送给后台管理员、客服或值班人员。</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item label="通道"
|
||||
>当前支持 Bark 与 WPush,两种通道可同时启用。</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item label="配置文件">{{
|
||||
notificationFilePath || '-'
|
||||
}}</el-descriptions-item>
|
||||
|
||||
+10
-4
@@ -5,15 +5,20 @@ type NotificationForm = {
|
||||
enabled: boolean
|
||||
barkEnabled: boolean
|
||||
barkServerUrl: string
|
||||
wpushEnabled: boolean
|
||||
testTitle: string
|
||||
testBody: string
|
||||
testUrl: string
|
||||
}
|
||||
|
||||
type NotificationStats = {
|
||||
configuredRecipientCount: number
|
||||
enabledRecipientCount: number
|
||||
barkConfiguredRecipientCount: number
|
||||
barkEnabledRecipientCount: number
|
||||
wpushConfiguredRecipientCount: number
|
||||
wpushEnabledRecipientCount: number
|
||||
barkReady: boolean
|
||||
wpushReady: boolean
|
||||
ready: boolean
|
||||
lastSuccessCount: number
|
||||
lastFailedCount: number
|
||||
scheduledJobEnabledCount: number
|
||||
@@ -36,11 +41,11 @@ defineProps<Props>()
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<span class="card-title">测试发送</span>
|
||||
<p class="card-desc">测试会发送给所有已启用且填写了 Device Key 的接收人。</p>
|
||||
<p class="card-desc">测试会发送给所有已启用且已填写 Bark Device Key 或 WPush API Key 的接收人。</p>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<el-button
|
||||
:disabled="!notificationStats.barkReady"
|
||||
:disabled="!notificationStats.ready"
|
||||
:loading="notificationTesting"
|
||||
type="primary"
|
||||
@click="handleNotificationTest"
|
||||
@@ -93,6 +98,7 @@ defineProps<Props>()
|
||||
size="small"
|
||||
class="mt-4"
|
||||
>
|
||||
<el-table-column prop="channel" label="通道" width="100" />
|
||||
<el-table-column label="接收人">
|
||||
<template #default="{ row }">{{
|
||||
row.recipientName || row.recipientKeyMasked || '-'
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
<script setup lang="ts">
|
||||
import type { EditableWpushRecipient } from '../../composables/types'
|
||||
|
||||
type NotificationForm = {
|
||||
enabled: boolean
|
||||
barkEnabled: boolean
|
||||
barkServerUrl: string
|
||||
wpushEnabled: boolean
|
||||
testTitle: string
|
||||
testBody: string
|
||||
testUrl: string
|
||||
}
|
||||
|
||||
type NotificationStats = {
|
||||
barkConfiguredRecipientCount: number
|
||||
barkEnabledRecipientCount: number
|
||||
wpushConfiguredRecipientCount: number
|
||||
wpushEnabledRecipientCount: number
|
||||
barkReady: boolean
|
||||
wpushReady: boolean
|
||||
ready: boolean
|
||||
lastSuccessCount: number
|
||||
lastFailedCount: number
|
||||
scheduledJobEnabledCount: number
|
||||
}
|
||||
|
||||
type Props = {
|
||||
notificationForm: NotificationForm
|
||||
wpushRecipients: EditableWpushRecipient[]
|
||||
notificationSaving: boolean
|
||||
notificationResultError: string
|
||||
notificationStats: NotificationStats
|
||||
addNotificationRecipient: () => void
|
||||
removeNotificationRecipient: (id: string) => void
|
||||
handleNotificationSaveConfig: () => void | Promise<void>
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card class="section-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<span class="card-title">WPush 通知</span>
|
||||
<p class="card-desc">
|
||||
已配置 {{ notificationStats.wpushConfiguredRecipientCount }} 人,启用
|
||||
{{ notificationStats.wpushEnabledRecipientCount }} 人。
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<el-button @click="addNotificationRecipient">新增接收人</el-button>
|
||||
<el-button
|
||||
:loading="notificationSaving"
|
||||
type="primary"
|
||||
@click="handleNotificationSaveConfig"
|
||||
>
|
||||
保存配置
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-alert
|
||||
v-if="notificationResultError"
|
||||
:title="notificationResultError"
|
||||
type="error"
|
||||
show-icon
|
||||
:closable="false"
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
<el-form label-width="auto" label-position="top" inline>
|
||||
<el-form-item>
|
||||
<el-switch v-model="notificationForm.wpushEnabled" active-text="启用 WPush 通道" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table :data="wpushRecipients" stripe size="small" class="mt-4">
|
||||
<el-table-column label="接收人" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.name" placeholder="例如:值班手机" size="small" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="API Key" min-width="220">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.apiKey" placeholder="WPush apikey" size="small" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.enabled" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button size="small" type="danger" text @click="removeNotificationRecipient(row.id)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="还没有 WPush 接收人。" :image-size="60" />
|
||||
</template>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.section-card {
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
+29
-7
@@ -1,8 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type { AdminNotificationTestResult, AdminScheduledJobRuntimeState } from '@/types/admin'
|
||||
import type { EditableNotificationRecipient, EditableScheduledJob } from '../../composables/types'
|
||||
import type {
|
||||
EditableNotificationRecipient,
|
||||
EditableScheduledJob,
|
||||
EditableWpushRecipient,
|
||||
} from '../../composables/types'
|
||||
import AdminNotificationInfoCard from './AdminNotificationInfoCard.vue'
|
||||
import AdminNotificationBarkCard from './AdminNotificationBarkCard.vue'
|
||||
import AdminNotificationWpushCard from './AdminNotificationWpushCard.vue'
|
||||
import AdminNotificationScheduledJobsCard from './AdminNotificationScheduledJobsCard.vue'
|
||||
import AdminNotificationTestCard from './AdminNotificationTestCard.vue'
|
||||
|
||||
@@ -10,6 +15,7 @@ type NotificationForm = {
|
||||
enabled: boolean
|
||||
barkEnabled: boolean
|
||||
barkServerUrl: string
|
||||
wpushEnabled: boolean
|
||||
testTitle: string
|
||||
testBody: string
|
||||
testUrl: string
|
||||
@@ -20,9 +26,13 @@ type ScheduledJobsForm = {
|
||||
}
|
||||
|
||||
type NotificationStats = {
|
||||
configuredRecipientCount: number
|
||||
enabledRecipientCount: number
|
||||
barkConfiguredRecipientCount: number
|
||||
barkEnabledRecipientCount: number
|
||||
wpushConfiguredRecipientCount: number
|
||||
wpushEnabledRecipientCount: number
|
||||
barkReady: boolean
|
||||
wpushReady: boolean
|
||||
ready: boolean
|
||||
lastSuccessCount: number
|
||||
lastFailedCount: number
|
||||
scheduledJobEnabledCount: number
|
||||
@@ -32,6 +42,7 @@ type Props = {
|
||||
notificationFilePath: string
|
||||
notificationForm: NotificationForm
|
||||
notificationRecipients: EditableNotificationRecipient[]
|
||||
wpushRecipients: EditableWpushRecipient[]
|
||||
notificationSaving: boolean
|
||||
notificationTesting: boolean
|
||||
notificationResultError: string
|
||||
@@ -43,8 +54,8 @@ type Props = {
|
||||
scheduledJobsSaving: boolean
|
||||
scheduledJobRunningId: string
|
||||
notificationStats: NotificationStats
|
||||
addNotificationRecipient: () => void
|
||||
removeNotificationRecipient: (id: string) => void
|
||||
addNotificationRecipient: (channel: 'bark' | 'wpush') => void
|
||||
removeNotificationRecipient: (channel: 'bark' | 'wpush', id: string) => void
|
||||
handleNotificationSaveConfig: () => void | Promise<void>
|
||||
handleNotificationTest: () => void | Promise<void>
|
||||
handleScheduledJobsSaveConfig: () => void | Promise<void>
|
||||
@@ -68,8 +79,19 @@ defineProps<Props>()
|
||||
:notification-saving="notificationSaving"
|
||||
:notification-result-error="notificationResultError"
|
||||
:notification-stats="notificationStats"
|
||||
:add-notification-recipient="addNotificationRecipient"
|
||||
:remove-notification-recipient="removeNotificationRecipient"
|
||||
:add-notification-recipient="() => addNotificationRecipient('bark')"
|
||||
:remove-notification-recipient="(id) => removeNotificationRecipient('bark', id)"
|
||||
:handle-notification-save-config="handleNotificationSaveConfig"
|
||||
/>
|
||||
|
||||
<AdminNotificationWpushCard
|
||||
:notification-form="notificationForm"
|
||||
:wpush-recipients="wpushRecipients"
|
||||
:notification-saving="notificationSaving"
|
||||
:notification-result-error="notificationResultError"
|
||||
:notification-stats="notificationStats"
|
||||
:add-notification-recipient="() => addNotificationRecipient('wpush')"
|
||||
:remove-notification-recipient="(id) => removeNotificationRecipient('wpush', id)"
|
||||
:handle-notification-save-config="handleNotificationSaveConfig"
|
||||
/>
|
||||
|
||||
|
||||
@@ -36,6 +36,13 @@ export type EditableNotificationRecipient = {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export type EditableWpushRecipient = {
|
||||
id: string
|
||||
name: string
|
||||
apiKey: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export type EditableScheduledJob = {
|
||||
id: string
|
||||
type: string
|
||||
|
||||
+68
-9
@@ -15,7 +15,11 @@ import type {
|
||||
AdminScheduledJobsResponse,
|
||||
} from '@/types/admin'
|
||||
|
||||
import type { EditableNotificationRecipient, EditableScheduledJob } from './types'
|
||||
import type {
|
||||
EditableNotificationRecipient,
|
||||
EditableScheduledJob,
|
||||
EditableWpushRecipient,
|
||||
} from './types'
|
||||
|
||||
export function useAdminNotificationPlatform() {
|
||||
const notificationFilePath = ref('')
|
||||
@@ -23,11 +27,13 @@ export function useAdminNotificationPlatform() {
|
||||
enabled: true,
|
||||
barkEnabled: true,
|
||||
barkServerUrl: 'https://api.day.app',
|
||||
wpushEnabled: true,
|
||||
testTitle: '订单系统测试通知',
|
||||
testBody: '这是一条 Bark 内部通知测试。',
|
||||
testBody: '这是一条内部通知测试。',
|
||||
testUrl: '',
|
||||
})
|
||||
const notificationRecipients = ref<EditableNotificationRecipient[]>([])
|
||||
const wpushRecipients = ref<EditableWpushRecipient[]>([])
|
||||
const notificationSaving = ref(false)
|
||||
const notificationTesting = ref(false)
|
||||
const notificationResultError = ref('')
|
||||
@@ -42,17 +48,37 @@ export function useAdminNotificationPlatform() {
|
||||
const scheduledJobRunningId = ref('')
|
||||
|
||||
const notificationStats = computed(() => {
|
||||
const enabledRecipients = notificationRecipients.value.filter(
|
||||
const enabledBarkRecipients = notificationRecipients.value.filter(
|
||||
(item) => item.enabled && item.deviceKey.trim(),
|
||||
)
|
||||
const enabledWpushRecipients = wpushRecipients.value.filter(
|
||||
(item) => item.enabled && item.apiKey.trim(),
|
||||
)
|
||||
|
||||
return {
|
||||
configuredRecipientCount: notificationRecipients.value.length,
|
||||
enabledRecipientCount: enabledRecipients.length,
|
||||
barkConfiguredRecipientCount: notificationRecipients.value.length,
|
||||
barkEnabledRecipientCount: enabledBarkRecipients.length,
|
||||
wpushConfiguredRecipientCount: wpushRecipients.value.length,
|
||||
wpushEnabledRecipientCount: enabledWpushRecipients.length,
|
||||
barkReady:
|
||||
notificationForm.value.enabled &&
|
||||
notificationForm.value.barkEnabled &&
|
||||
enabledRecipients.length > 0,
|
||||
enabledBarkRecipients.length > 0,
|
||||
wpushReady:
|
||||
notificationForm.value.enabled &&
|
||||
notificationForm.value.wpushEnabled &&
|
||||
enabledWpushRecipients.length > 0,
|
||||
ready:
|
||||
(
|
||||
notificationForm.value.enabled &&
|
||||
notificationForm.value.barkEnabled &&
|
||||
enabledBarkRecipients.length > 0
|
||||
) ||
|
||||
(
|
||||
notificationForm.value.enabled &&
|
||||
notificationForm.value.wpushEnabled &&
|
||||
enabledWpushRecipients.length > 0
|
||||
),
|
||||
lastSuccessCount: notificationTestResult.value?.successCount || 0,
|
||||
lastFailedCount: notificationTestResult.value?.failedCount || 0,
|
||||
scheduledJobEnabledCount: scheduledJobs.value.filter((item) => item.enabled).length,
|
||||
@@ -65,12 +91,19 @@ export function useAdminNotificationPlatform() {
|
||||
notificationForm.value.barkEnabled = data.source.channels.bark.enabled !== false
|
||||
notificationForm.value.barkServerUrl =
|
||||
data.source.channels.bark.serverUrl || 'https://api.day.app'
|
||||
notificationForm.value.wpushEnabled = data.source.channels.wpush.enabled !== false
|
||||
notificationRecipients.value = data.source.channels.bark.recipients.map((item) => ({
|
||||
id: item.id || crypto.randomUUID(),
|
||||
name: item.name,
|
||||
deviceKey: item.deviceKey,
|
||||
enabled: item.enabled !== false,
|
||||
}))
|
||||
wpushRecipients.value = data.source.channels.wpush.recipients.map((item) => ({
|
||||
id: item.id || crypto.randomUUID(),
|
||||
name: item.name,
|
||||
apiKey: item.apiKey,
|
||||
enabled: item.enabled !== false,
|
||||
}))
|
||||
}
|
||||
|
||||
function hydrateScheduledJobsConfig(data: AdminScheduledJobsResponse) {
|
||||
@@ -91,7 +124,17 @@ export function useAdminNotificationPlatform() {
|
||||
scheduledJobRuntime.value = data.runtime || []
|
||||
}
|
||||
|
||||
function addNotificationRecipient() {
|
||||
function addNotificationRecipient(channel: 'bark' | 'wpush') {
|
||||
if (channel === 'wpush') {
|
||||
wpushRecipients.value.unshift({
|
||||
id: crypto.randomUUID(),
|
||||
name: '',
|
||||
apiKey: '',
|
||||
enabled: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
notificationRecipients.value.unshift({
|
||||
id: crypto.randomUUID(),
|
||||
name: '',
|
||||
@@ -100,7 +143,12 @@ export function useAdminNotificationPlatform() {
|
||||
})
|
||||
}
|
||||
|
||||
function removeNotificationRecipient(id: string) {
|
||||
function removeNotificationRecipient(channel: 'bark' | 'wpush', id: string) {
|
||||
if (channel === 'wpush') {
|
||||
wpushRecipients.value = wpushRecipients.value.filter((item) => item.id !== id)
|
||||
return
|
||||
}
|
||||
|
||||
notificationRecipients.value = notificationRecipients.value.filter((item) => item.id !== id)
|
||||
}
|
||||
|
||||
@@ -119,6 +167,16 @@ export function useAdminNotificationPlatform() {
|
||||
enabled: item.enabled,
|
||||
})),
|
||||
},
|
||||
wpush: {
|
||||
enabled: notificationForm.value.wpushEnabled,
|
||||
recipients: wpushRecipients.value.map((item) => ({
|
||||
id: item.id,
|
||||
name: item.name.trim(),
|
||||
apiKey: item.apiKey.trim(),
|
||||
apiKeyMasked: '',
|
||||
enabled: item.enabled,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -176,7 +234,7 @@ export function useAdminNotificationPlatform() {
|
||||
if (response.data.successCount > 0) {
|
||||
showSuccess(`内部通知测试完成,成功 ${response.data.successCount} 个`)
|
||||
} else {
|
||||
showError('内部通知测试未成功发送,请检查 Bark 配置')
|
||||
showError('内部通知测试未成功发送,请检查通知通道配置')
|
||||
}
|
||||
} catch (error) {
|
||||
notificationResultError.value = error instanceof Error ? error.message : '内部通知测试失败'
|
||||
@@ -243,6 +301,7 @@ export function useAdminNotificationPlatform() {
|
||||
notificationFilePath,
|
||||
notificationForm,
|
||||
notificationRecipients,
|
||||
wpushRecipients,
|
||||
notificationSaving,
|
||||
notificationTesting,
|
||||
notificationResultError,
|
||||
|
||||
Reference in New Issue
Block a user