Files
stream.ui/src/components/PopupAdsRuntime.vue
claude 8515498ade feat: add PopupAd and AdminPopupAd interfaces with CRUD operations
- Introduced PopupAd and AdminPopupAd interfaces in common.ts.
- Implemented encoding, decoding, and JSON conversion methods for both PopupAd and AdminPopupAd.
- Added new RPC methods for managing PopupAds in admin.ts and me.ts, including list, create, update, and delete functionalities.
- Integrated PopupAdsClient in grpcClient.ts for gRPC communication.
- Updated auth store to handle real-time notifications for user-specific topics.
- Modified tsconfig.json to include auto-imports and components type definitions.
2026-03-29 06:42:37 +00:00

76 lines
2.0 KiB
Vue

<script setup lang="ts">
import { client as rpcClient } from '@/api/rpcclient';
import ClientOnly from '@/components/ClientOnly';
import { onMounted, onBeforeUnmount } from 'vue';
let activeItem: any | null = null;
let clickHandler: ((event: MouseEvent) => void) | null = null;
let scriptNode: HTMLScriptElement | null = null;
let triggerCount = 0;
const triggerKey = (id: string) => `popup_ad_triggers:${id}`;
const cleanupScript = () => {
if (scriptNode?.parentNode) {
scriptNode.parentNode.removeChild(scriptNode);
}
scriptNode = null;
};
const attachUrlHandler = () => {
if (!activeItem?.id || typeof window === 'undefined') return;
const maxTriggers = Number(activeItem.maxTriggersPerSession || 1);
triggerCount = Number(sessionStorage.getItem(triggerKey(activeItem.id)) || '0');
clickHandler = () => {
if (!activeItem?.value || triggerCount >= maxTriggers) return;
triggerCount += 1;
sessionStorage.setItem(triggerKey(activeItem.id), String(triggerCount));
window.open(activeItem.value, '_blank', 'noopener,noreferrer');
};
window.addEventListener('click', clickHandler, { capture: true });
};
const attachScript = () => {
if (!activeItem?.value || typeof document === 'undefined') return;
cleanupScript();
scriptNode = document.createElement('script');
scriptNode.async = true;
scriptNode.text = activeItem.value;
document.body.appendChild(scriptNode);
};
onMounted(async () => {
try {
const response = await rpcClient.getActivePopupAd();
activeItem = response.item || null;
if (!activeItem?.isActive) return;
if (activeItem.type === 'script') {
attachScript();
return;
}
if (activeItem.type === 'url') {
attachUrlHandler();
}
} catch (error) {
console.error(error);
}
});
onBeforeUnmount(() => {
if (clickHandler && typeof window !== 'undefined') {
window.removeEventListener('click', clickHandler, { capture: true } as EventListenerOptions);
}
cleanupScript();
});
</script>
<template>
<ClientOnly>
<span class="hidden" />
</ClientOnly>
</template>