通知系统-1

This commit is contained in:
yml2213
2026-05-14 17:29:12 +08:00
parent 91d74b3e59
commit b6c493d5e7
22 changed files with 1314 additions and 11 deletions
@@ -0,0 +1,171 @@
<script setup lang="ts">
import type { AdminNotificationTestResult } from '@/types/admin'
import type { EditableNotificationRecipient } from '@/composables/admin/platform-shops/types'
type Props = {
notificationFilePath: string
notificationForm: {
enabled: boolean
barkEnabled: boolean
barkServerUrl: string
testTitle: string
testBody: string
testUrl: string
}
notificationRecipients: EditableNotificationRecipient[]
notificationSaving: boolean
notificationTesting: boolean
notificationResultError: string
notificationTestResult: AdminNotificationTestResult | null
notificationStats: {
configuredRecipientCount: number
enabledRecipientCount: number
barkReady: boolean
lastSuccessCount: number
lastFailedCount: number
}
addNotificationRecipient: () => void
removeNotificationRecipient: (id: string) => void
handleNotificationSaveConfig: () => void | Promise<void>
handleNotificationTest: () => void | Promise<void>
}
defineProps<Props>()
</script>
<template>
<section class="meta-card">
<div class="meta-line">
<span class="meta-label">职责</span>
<span>内部运营通知仅发送给后台管理员客服或值班人员</span>
</div>
<div class="meta-line">
<span class="meta-label">配置文件</span>
<span>{{ notificationFilePath || '-' }}</span>
</div>
</section>
<section class="table-card">
<div class="section-title-row">
<div>
<h3>Bark 通知</h3>
<p>已配置 {{ notificationStats.configuredRecipientCount }} 启用 {{ notificationStats.enabledRecipientCount }} </p>
</div>
<div class="section-actions">
<el-button round @click="addNotificationRecipient">新增接收人</el-button>
<el-button :loading="notificationSaving" round type="primary" @click="handleNotificationSaveConfig">保存配置</el-button>
</div>
</div>
<p v-if="notificationResultError" class="error-copy">{{ notificationResultError }}</p>
<div class="form-grid">
<label class="checkbox-line">
<input v-model="notificationForm.enabled" class="checkbox-box" type="checkbox" />
<span>启用内部通知</span>
</label>
<label class="checkbox-line">
<input v-model="notificationForm.barkEnabled" class="checkbox-box" type="checkbox" />
<span>启用 Bark 通道</span>
</label>
<label class="field-block field-wide">
<span>Bark 服务地址</span>
<input v-model="notificationForm.barkServerUrl" class="text-input" placeholder="https://api.day.app" />
</label>
</div>
<table class="data-table">
<thead>
<tr>
<th>接收人</th>
<th>Device Key</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in notificationRecipients" :key="item.id">
<td>
<input v-model="item.name" class="text-input" placeholder="例如:客服A" />
</td>
<td>
<input v-model="item.deviceKey" class="text-input" placeholder="Bark device key" />
</td>
<td>
<label class="checkbox-line">
<input v-model="item.enabled" class="checkbox-box" type="checkbox" />
<span>{{ item.enabled ? '启用' : '停用' }}</span>
</label>
</td>
<td>
<el-button link type="danger" @click="removeNotificationRecipient(item.id)">删除</el-button>
</td>
</tr>
<tr v-if="notificationRecipients.length === 0">
<td colspan="4" class="empty-inline">还没有 Bark 接收人</td>
</tr>
</tbody>
</table>
</section>
<section class="table-card">
<div class="section-title-row">
<div>
<h3>测试发送</h3>
<p>测试会发送给所有已启用且填写了 Device Key 的接收人</p>
</div>
<div class="section-actions">
<el-button :disabled="!notificationStats.barkReady" :loading="notificationTesting" round type="primary" @click="handleNotificationTest">发送测试</el-button>
</div>
</div>
<div class="form-grid">
<label class="field-block">
<span>标题</span>
<input v-model="notificationForm.testTitle" class="text-input" />
</label>
<label class="field-block field-wide">
<span>内容</span>
<input v-model="notificationForm.testBody" class="text-input" />
</label>
<label class="field-block field-wide">
<span>跳转链接</span>
<input v-model="notificationForm.testUrl" class="text-input" placeholder="可选" />
</label>
</div>
<div v-if="notificationTestResult" class="result-grid">
<div class="result-card">
<span class="result-label">成功</span>
<strong>{{ notificationTestResult.successCount }}</strong>
</div>
<div class="result-card">
<span class="result-label">失败</span>
<strong>{{ notificationTestResult.failedCount }}</strong>
</div>
<div class="result-card">
<span class="result-label">通道</span>
<strong>{{ notificationTestResult.channel || '-' }}</strong>
</div>
</div>
<table v-if="notificationTestResult" class="data-table">
<thead>
<tr>
<th>接收人</th>
<th>结果</th>
<th>状态码</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr v-for="item in notificationTestResult.results" :key="item.recipientId || item.recipientKeyMasked">
<td>{{ item.recipientName || item.recipientKeyMasked || '-' }}</td>
<td>{{ item.ok ? '成功' : '失败' }}</td>
<td>{{ item.status || '-' }}</td>
<td>{{ item.errorMessage || '-' }}</td>
</tr>
</tbody>
</table>
</section>
</template>