From 66713b110f60f33f7b532f8bccd9ed8e42b9a66a Mon Sep 17 00:00:00 2001 From: nepiedg Date: Sat, 4 Apr 2026 04:02:17 +0800 Subject: [PATCH] feat(marketing): add ad placement management UI - CRUD for ad placements (rewarded video, banner, interstitial) - Integrated into marketing management page with table and dialog Made-with: Cursor --- src/api/marketing.js | 30 ++++++ src/views/marketing/index.vue | 168 +++++++++++++++++++++++++++++++++- 2 files changed, 196 insertions(+), 2 deletions(-) diff --git a/src/api/marketing.js b/src/api/marketing.js index 8d9fb93..e04d220 100644 --- a/src/api/marketing.js +++ b/src/api/marketing.js @@ -84,3 +84,33 @@ export function deleteMarketingTemplate(id) { method: 'delete' }) } + +export function getAdPlacements() { + return request({ + url: '/api/admin/marketing/ad-placements', + method: 'get' + }) +} + +export function createAdPlacement(data) { + return request({ + url: '/api/admin/marketing/ad-placements', + method: 'post', + data + }) +} + +export function updateAdPlacement(id, data) { + return request({ + url: `/api/admin/marketing/ad-placements/${id}`, + method: 'put', + data + }) +} + +export function deleteAdPlacement(id) { + return request({ + url: `/api/admin/marketing/ad-placements/${id}`, + method: 'delete' + }) +} diff --git a/src/views/marketing/index.vue b/src/views/marketing/index.vue index 7eab911..bc0c22b 100644 --- a/src/views/marketing/index.vue +++ b/src/views/marketing/index.vue @@ -152,6 +152,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { const candidates = [ data?.[key], @@ -369,9 +465,77 @@ const loadStats = async () => { } } +const loadAdPlacements = async () => { + adsLoading.value = true + try { + const res = await getAdPlacements() + adPlacements.value = res.data || [] + } catch (error) { + errorMessage.value = '加载广告位失败' + } finally { + adsLoading.value = false + } +} + +const openAdDialog = (row) => { + if (!row) { + adForm.id = null + adForm.name = '' + adForm.ad_type = 'rewarded_video' + adForm.ad_unit_id = '' + adForm.mini_program_id = 3 + adForm.statusBool = true + adForm.description = '' + } else { + adForm.id = row.id + adForm.name = row.name || '' + adForm.ad_type = row.ad_type || 'rewarded_video' + adForm.ad_unit_id = row.ad_unit_id || '' + adForm.mini_program_id = row.mini_program_id || 3 + adForm.statusBool = row.status === 1 + adForm.description = row.description || '' + } + adDialogVisible.value = true +} + +const saveAd = async () => { + if (!adForm.name.trim()) { + ElMessage.warning('请填写广告位名称') + return + } + adSaving.value = true + try { + const payload = { + name: adForm.name.trim(), + ad_type: adForm.ad_type, + ad_unit_id: adForm.ad_unit_id.trim(), + mini_program_id: adForm.mini_program_id, + status: adForm.statusBool ? 1 : 0, + description: adForm.description.trim() + } + if (adForm.id) { + await updateAdPlacement(adForm.id, payload) + ElMessage.success('广告位更新成功') + } else { + await createAdPlacement(payload) + ElMessage.success('广告位创建成功') + } + adDialogVisible.value = false + await loadAdPlacements() + } finally { + adSaving.value = false + } +} + +const handleDeleteAd = async (id) => { + await deleteAdPlacement(id) + ElMessage.success('广告位删除成功') + await loadAdPlacements() +} + const loadAll = async () => { errorMessage.value = '' - await Promise.all([loadCategories(), loadTemplates(), loadTemplateCount(), loadStats()]) + await Promise.all([loadCategories(), loadTemplates(), loadTemplateCount(), loadStats(), loadAdPlacements()]) } const resetCategoryForm = () => {