通知系统-1
This commit is contained in:
Vendored
+1
@@ -16,6 +16,7 @@ declare module 'vue' {
|
||||
AdminPlatformCloudtentaclesSection: typeof import('./components/admin/AdminPlatformCloudtentaclesSection.vue')['default']
|
||||
AdminPlatformKuaishouEticketSection: typeof import('./components/admin/AdminPlatformKuaishouEticketSection.vue')['default']
|
||||
AdminPlatformNinetyoneSection: typeof import('./components/admin/AdminPlatformNinetyoneSection.vue')['default']
|
||||
AdminPlatformNotificationSection: typeof import('./components/admin/AdminPlatformNotificationSection.vue')['default']
|
||||
AdminResultCard: typeof import('./components/admin/AdminResultCard.vue')['default']
|
||||
AdminStatusTag: typeof import('./components/admin/AdminStatusTag.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
|
||||
@@ -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>
|
||||
@@ -1,4 +1,4 @@
|
||||
export type PlatformTab = 'agiso' | 'ninetyone' | 'kuaishouEticket' | 'cloudtentacles'
|
||||
export type PlatformTab = 'agiso' | 'notifications' | 'ninetyone' | 'kuaishouEticket' | 'cloudtentacles'
|
||||
|
||||
export type EditableDefaults = {
|
||||
messageTemplate: string
|
||||
@@ -23,3 +23,10 @@ export type EditableKuaishouEticketShop = {
|
||||
userAvatar: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export type EditableNotificationRecipient = {
|
||||
id: string
|
||||
name: string
|
||||
deviceKey: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { showError, showSuccess } from '@/lib/feedback'
|
||||
import {
|
||||
saveAdminNotificationConfig,
|
||||
testAdminNotification,
|
||||
} from '@/services/admin'
|
||||
import type {
|
||||
AdminNotificationConfig,
|
||||
AdminNotificationTestResult,
|
||||
} from '@/types/admin'
|
||||
|
||||
import type { EditableNotificationRecipient } from './types'
|
||||
|
||||
export function useAdminNotificationPlatform() {
|
||||
const notificationFilePath = ref('')
|
||||
const notificationForm = ref({
|
||||
enabled: true,
|
||||
barkEnabled: true,
|
||||
barkServerUrl: 'https://api.day.app',
|
||||
testTitle: '订单系统测试通知',
|
||||
testBody: '这是一条 Bark 内部通知测试。',
|
||||
testUrl: '',
|
||||
})
|
||||
const notificationRecipients = ref<EditableNotificationRecipient[]>([])
|
||||
const notificationSaving = ref(false)
|
||||
const notificationTesting = ref(false)
|
||||
const notificationResultError = ref('')
|
||||
const notificationTestResult = ref<AdminNotificationTestResult | null>(null)
|
||||
|
||||
const notificationStats = computed(() => {
|
||||
const enabledRecipients = notificationRecipients.value.filter((item) => item.enabled && item.deviceKey.trim())
|
||||
|
||||
return {
|
||||
configuredRecipientCount: notificationRecipients.value.length,
|
||||
enabledRecipientCount: enabledRecipients.length,
|
||||
barkReady: notificationForm.value.enabled && notificationForm.value.barkEnabled && enabledRecipients.length > 0,
|
||||
lastSuccessCount: notificationTestResult.value?.successCount || 0,
|
||||
lastFailedCount: notificationTestResult.value?.failedCount || 0,
|
||||
}
|
||||
})
|
||||
|
||||
function hydrateNotificationConfig(data: {
|
||||
filePath: string
|
||||
source: AdminNotificationConfig
|
||||
}) {
|
||||
notificationFilePath.value = data.filePath
|
||||
notificationForm.value.enabled = data.source.enabled !== false
|
||||
notificationForm.value.barkEnabled = data.source.channels.bark.enabled !== false
|
||||
notificationForm.value.barkServerUrl = data.source.channels.bark.serverUrl || 'https://api.day.app'
|
||||
notificationRecipients.value = data.source.channels.bark.recipients.map((item) => ({
|
||||
id: item.id || crypto.randomUUID(),
|
||||
name: item.name,
|
||||
deviceKey: item.deviceKey,
|
||||
enabled: item.enabled !== false,
|
||||
}))
|
||||
}
|
||||
|
||||
function addNotificationRecipient() {
|
||||
notificationRecipients.value.unshift({
|
||||
id: crypto.randomUUID(),
|
||||
name: '',
|
||||
deviceKey: '',
|
||||
enabled: true,
|
||||
})
|
||||
}
|
||||
|
||||
function removeNotificationRecipient(id: string) {
|
||||
notificationRecipients.value = notificationRecipients.value.filter((item) => item.id !== id)
|
||||
}
|
||||
|
||||
function buildNotificationConfigPayload(): AdminNotificationConfig {
|
||||
return {
|
||||
enabled: notificationForm.value.enabled,
|
||||
channels: {
|
||||
bark: {
|
||||
enabled: notificationForm.value.barkEnabled,
|
||||
serverUrl: notificationForm.value.barkServerUrl.trim() || 'https://api.day.app',
|
||||
recipients: notificationRecipients.value.map((item) => ({
|
||||
id: item.id,
|
||||
name: item.name.trim(),
|
||||
deviceKey: item.deviceKey.trim(),
|
||||
deviceKeyMasked: '',
|
||||
enabled: item.enabled,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async function handleNotificationSaveConfig() {
|
||||
notificationSaving.value = true
|
||||
notificationResultError.value = ''
|
||||
|
||||
try {
|
||||
const response = await saveAdminNotificationConfig(buildNotificationConfigPayload())
|
||||
notificationFilePath.value = response.data.filePath
|
||||
hydrateNotificationConfig(response.data)
|
||||
showSuccess('内部通知配置已保存')
|
||||
} catch (error) {
|
||||
notificationResultError.value = error instanceof Error ? error.message : '内部通知配置保存失败'
|
||||
showError(notificationResultError.value)
|
||||
} finally {
|
||||
notificationSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleNotificationTest() {
|
||||
notificationTesting.value = true
|
||||
notificationResultError.value = ''
|
||||
notificationTestResult.value = null
|
||||
|
||||
try {
|
||||
const saved = await saveAdminNotificationConfig(buildNotificationConfigPayload())
|
||||
notificationFilePath.value = saved.data.filePath
|
||||
hydrateNotificationConfig(saved.data)
|
||||
|
||||
const response = await testAdminNotification({
|
||||
title: notificationForm.value.testTitle.trim(),
|
||||
body: notificationForm.value.testBody.trim(),
|
||||
url: notificationForm.value.testUrl.trim(),
|
||||
})
|
||||
notificationTestResult.value = response.data
|
||||
if (response.data.successCount > 0) {
|
||||
showSuccess(`内部通知测试完成,成功 ${response.data.successCount} 个`)
|
||||
} else {
|
||||
showError('内部通知测试未成功发送,请检查 Bark 配置')
|
||||
}
|
||||
} catch (error) {
|
||||
notificationResultError.value = error instanceof Error ? error.message : '内部通知测试失败'
|
||||
showError(notificationResultError.value)
|
||||
} finally {
|
||||
notificationTesting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
notificationFilePath,
|
||||
notificationForm,
|
||||
notificationRecipients,
|
||||
notificationSaving,
|
||||
notificationTesting,
|
||||
notificationResultError,
|
||||
notificationTestResult,
|
||||
notificationStats,
|
||||
hydrateNotificationConfig,
|
||||
addNotificationRecipient,
|
||||
removeNotificationRecipient,
|
||||
handleNotificationSaveConfig,
|
||||
handleNotificationTest,
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ import type {
|
||||
AdminFulfillmentLookupResult,
|
||||
AdminNinetyoneOrderActionResult,
|
||||
AdminNinetyoneOrderListResult,
|
||||
AdminNotificationConfig,
|
||||
AdminNotificationTestResult,
|
||||
AdminKuaishouCloudFulfillmentConfig,
|
||||
AdminKuaishouEticketConsumeResult,
|
||||
AdminKuaishouEticketDetailResult,
|
||||
@@ -41,6 +43,28 @@ export function saveAdminAgisoShopConfigs(payload: {
|
||||
}>('/api/v1/admin/platform-config/agiso-shops', payload)
|
||||
}
|
||||
|
||||
export function fetchAdminNotificationConfig() {
|
||||
return apiGet<{
|
||||
filePath: string
|
||||
source: AdminNotificationConfig
|
||||
}>('/api/v1/admin/platform-config/notifications')
|
||||
}
|
||||
|
||||
export function saveAdminNotificationConfig(payload: AdminNotificationConfig) {
|
||||
return apiPost<{
|
||||
filePath: string
|
||||
source: AdminNotificationConfig
|
||||
}>('/api/v1/admin/platform-config/notifications', payload as unknown as Record<string, unknown>)
|
||||
}
|
||||
|
||||
export function testAdminNotification(payload: {
|
||||
title?: string
|
||||
body?: string
|
||||
url?: string
|
||||
}) {
|
||||
return apiPost<AdminNotificationTestResult>('/api/v1/admin/platform-config/notifications/test', payload)
|
||||
}
|
||||
|
||||
export function fetchAdminNinetyoneOrders(params: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
|
||||
@@ -164,6 +164,44 @@ export interface AdminKuaishouEticketConsumeResult {
|
||||
raw: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface AdminNotificationBarkRecipient {
|
||||
id: string
|
||||
name: string
|
||||
deviceKey: string
|
||||
deviceKeyMasked: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export interface AdminNotificationConfig {
|
||||
enabled: boolean
|
||||
channels: {
|
||||
bark: {
|
||||
enabled: boolean
|
||||
serverUrl: string
|
||||
recipients: AdminNotificationBarkRecipient[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface AdminNotificationSendResult {
|
||||
recipientId: string
|
||||
recipientName: string
|
||||
recipientKeyMasked: string
|
||||
ok: boolean
|
||||
status: number
|
||||
errorMessage: string
|
||||
response: unknown
|
||||
}
|
||||
|
||||
export interface AdminNotificationTestResult {
|
||||
enabled: boolean
|
||||
channel: string
|
||||
successCount: number
|
||||
failedCount: number
|
||||
skippedCount: number
|
||||
results: AdminNotificationSendResult[]
|
||||
}
|
||||
|
||||
export interface AdminNinetyoneOrderItem {
|
||||
orderId: number
|
||||
orderNo: string
|
||||
|
||||
@@ -4,16 +4,19 @@ import { onMounted, ref } from 'vue'
|
||||
import AdminPlatformAgisoSection from '@/components/admin/AdminPlatformAgisoSection.vue'
|
||||
import AdminPlatformCloudtentaclesSection from '@/components/admin/AdminPlatformCloudtentaclesSection.vue'
|
||||
import AdminPlatformNinetyoneSection from '@/components/admin/AdminPlatformNinetyoneSection.vue'
|
||||
import AdminPlatformNotificationSection from '@/components/admin/AdminPlatformNotificationSection.vue'
|
||||
import AdminPlatformKuaishouEticketSection from '@/components/admin/AdminPlatformKuaishouEticketSection.vue'
|
||||
import { useAdminAgisoPlatform } from '@/composables/admin/platform-shops/useAdminAgisoPlatform'
|
||||
import { useAdminCloudtentaclesPlatform } from '@/composables/admin/platform-shops/useAdminCloudtentaclesPlatform'
|
||||
import { useAdminNinetyonePlatform } from '@/composables/admin/platform-shops/useAdminNinetyonePlatform'
|
||||
import { useAdminNotificationPlatform } from '@/composables/admin/platform-shops/useAdminNotificationPlatform'
|
||||
import { useAdminKuaishouEticketPlatform } from '@/composables/admin/platform-shops/useAdminKuaishouEticketPlatform'
|
||||
import type { PlatformTab } from '@/composables/admin/platform-shops/types'
|
||||
import {
|
||||
fetchAdminAgisoShopConfigs,
|
||||
fetchAdminCloudtentaclesSourceConfig,
|
||||
fetchAdminKuaishouEticketSourceConfig,
|
||||
fetchAdminNotificationConfig,
|
||||
} from '@/services/admin'
|
||||
import { hasAdminRole } from '@/utils/admin-auth'
|
||||
import '@/styles/admin-platform-shops.css'
|
||||
@@ -55,6 +58,22 @@ const {
|
||||
handleNinetyoneFailOrder,
|
||||
} = useAdminNinetyonePlatform()
|
||||
|
||||
const {
|
||||
notificationFilePath,
|
||||
notificationForm,
|
||||
notificationRecipients,
|
||||
notificationSaving,
|
||||
notificationTesting,
|
||||
notificationResultError,
|
||||
notificationTestResult,
|
||||
notificationStats,
|
||||
hydrateNotificationConfig,
|
||||
addNotificationRecipient,
|
||||
removeNotificationRecipient,
|
||||
handleNotificationSaveConfig,
|
||||
handleNotificationTest,
|
||||
} = useAdminNotificationPlatform()
|
||||
|
||||
const {
|
||||
kuaishouEticketFilePath,
|
||||
kuaishouEticketShops,
|
||||
@@ -132,13 +151,15 @@ async function loadConfigs() {
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
const [agisoResponse, kuaishouEticketResponse, cloudtentaclesResponse] = await Promise.all([
|
||||
const [agisoResponse, notificationResponse, kuaishouEticketResponse, cloudtentaclesResponse] = await Promise.all([
|
||||
fetchAdminAgisoShopConfigs(),
|
||||
fetchAdminNotificationConfig(),
|
||||
fetchAdminKuaishouEticketSourceConfig(),
|
||||
fetchAdminCloudtentaclesSourceConfig(),
|
||||
])
|
||||
|
||||
hydrateAgisoConfig(agisoResponse.data)
|
||||
hydrateNotificationConfig(notificationResponse.data)
|
||||
hydrateKuaishouEticketConfig(kuaishouEticketResponse.data)
|
||||
hydrateCloudtentaclesConfig(cloudtentaclesResponse.data)
|
||||
await loadNinetyoneOrders(1)
|
||||
@@ -198,6 +219,23 @@ onMounted(loadConfigs)
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
:class="['platform-overview-card', { 'is-active': activePlatform === 'notifications' }]"
|
||||
@click="switchPlatform('notifications')"
|
||||
>
|
||||
<div class="platform-head">
|
||||
<span class="platform-badge">内部通知</span>
|
||||
<span class="platform-tag">Bark / 值班</span>
|
||||
</div>
|
||||
<strong>{{ notificationStats.enabledRecipientCount }}</strong>
|
||||
<span>启用接收人</span>
|
||||
<div class="platform-metrics">
|
||||
<span>配置 {{ notificationStats.configuredRecipientCount }} 人</span>
|
||||
<span>最近成功 {{ notificationStats.lastSuccessCount }} 个</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
:class="['platform-overview-card', { 'is-active': activePlatform === 'ninetyone' }]"
|
||||
@@ -266,6 +304,13 @@ onMounted(loadConfigs)
|
||||
>
|
||||
91卡券接入
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="['switch-chip', { 'is-active': activePlatform === 'notifications' }]"
|
||||
@click="switchPlatform('notifications')"
|
||||
>
|
||||
内部通知
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="['switch-chip', { 'is-active': activePlatform === 'kuaishouEticket' }]"
|
||||
@@ -314,6 +359,22 @@ onMounted(loadConfigs)
|
||||
:handle-ninetyone-fail-order="handleNinetyoneFailOrder"
|
||||
/>
|
||||
|
||||
<AdminPlatformNotificationSection
|
||||
v-else-if="activePlatform === 'notifications'"
|
||||
:notification-file-path="notificationFilePath"
|
||||
:notification-form="notificationForm"
|
||||
:notification-recipients="notificationRecipients"
|
||||
:notification-saving="notificationSaving"
|
||||
:notification-testing="notificationTesting"
|
||||
:notification-result-error="notificationResultError"
|
||||
:notification-test-result="notificationTestResult"
|
||||
:notification-stats="notificationStats"
|
||||
:add-notification-recipient="addNotificationRecipient"
|
||||
:remove-notification-recipient="removeNotificationRecipient"
|
||||
:handle-notification-save-config="handleNotificationSaveConfig"
|
||||
:handle-notification-test="handleNotificationTest"
|
||||
/>
|
||||
|
||||
<AdminPlatformKuaishouEticketSection
|
||||
v-else-if="activePlatform === 'kuaishouEticket'"
|
||||
:kuaishou-eticket-file-path="kuaishouEticketFilePath"
|
||||
|
||||
Reference in New Issue
Block a user