diff --git a/hunliji-api/router/routers.go b/hunliji-api/router/routers.go index a652c55..61bab0e 100644 --- a/hunliji-api/router/routers.go +++ b/hunliji-api/router/routers.go @@ -215,6 +215,8 @@ func registerAPI(api *gin.RouterGroup) { api.GET("/gift", handleGiftStatus) api.POST("/gift", handleCreateGift) api.GET("/gift/stats", handleGiftStats) + api.GET("/gift/list", handleGiftList) + api.DELETE("/gift/:id", handleDeleteGift) api.GET("/gift/costs", handleGetGiftCosts) api.POST("/gift/costs", handleSaveGiftCosts) api.POST("/cash-gift", handleCreateCashGift) @@ -724,6 +726,42 @@ func handleGiftStats(c *gin.Context) { }) } +func handleGiftList(c *gin.Context) { + if !utils.RequireAdmin(c) { + return + } + var list []models.SiteGift + db.Order("created_at desc, id desc").Find(&list) + c.JSON(200, gin.H{ + "code": 200, + "data": gin.H{ + "list": list, + "count": len(list), + }, + }) +} + +func handleDeleteGift(c *gin.Context) { + if !utils.RequireAdmin(c) { + return + } + id := strings.TrimSpace(c.Param("id")) + if id == "" { + c.JSON(400, gin.H{"error": "缺少 ID"}) + return + } + res := db.Delete(&models.SiteGift{}, id) + if res.Error != nil { + c.JSON(500, gin.H{"error": "删除失败"}) + return + } + if res.RowsAffected == 0 { + c.JSON(404, gin.H{"error": "记录不存在"}) + return + } + c.JSON(200, gin.H{"code": 200, "msg": "已删除"}) +} + func handleGetGiftCosts(c *gin.Context) { if !utils.RequireAdmin(c) { return diff --git a/vite-tailwindcss/src/api/wedding.js b/vite-tailwindcss/src/api/wedding.js index 56f4838..71f702d 100644 --- a/vite-tailwindcss/src/api/wedding.js +++ b/vite-tailwindcss/src/api/wedding.js @@ -154,6 +154,14 @@ export function getGiftStats() { return service.get('/gift/stats') } +export function getGiftList() { + return service.get('/gift/list') +} + +export function deleteGift(id) { + return service.delete(`/gift/${id}`) +} + export function getGiftCosts() { return service.get('/gift/costs') } diff --git a/vite-tailwindcss/src/views/admin/AdminEditor.vue b/vite-tailwindcss/src/views/admin/AdminEditor.vue index ad36732..a0a3c37 100644 --- a/vite-tailwindcss/src/views/admin/AdminEditor.vue +++ b/vite-tailwindcss/src/views/admin/AdminEditor.vue @@ -197,7 +197,7 @@
礼物统计
各礼物收到次数 · 合计 {{ giftStats.total }}
- + 刷新 @@ -234,6 +234,41 @@ /> + +
+
+
礼物明细
+
共 {{ giftList.length }} 条送礼记录
+
+ + 刷新列表 + +
+ + + @@ -1301,7 +1336,7 @@ import { CanvasRenderer } from 'echarts/renderers' import { getConfigSection, saveConfigSection, uploadImage, getRsvpList, deleteRsvp, getUploadConfig, saveUploadConfig, getDanmakuList, updateDanmakuStatus, getVisitStats, getVisitList, - getPosterConfig, savePosterConfig, getGiftStats, saveGiftCosts, + getPosterConfig, savePosterConfig, getGiftStats, getGiftList, deleteGift, saveGiftCosts, getCashGiftList, updateCashGift, deleteCashGift, submitCashGift, getCashGiftNotes, saveCashGiftNotes, getCashGiftViewPass, saveCashGiftViewPass, @@ -1311,7 +1346,7 @@ import { useAdminStore } from '@/stores/admin' import ImageField from '@/components/ImageField.vue' import { BORDER_STYLES, borderClass } from '@/composables/borderStyles' import { resolveDanmakuSwatch } from '@/utils/danmakuColors' -import { GIFT_TYPES, emptyGiftCosts, DEFAULT_GIFT_COSTS } from '@/utils/giftTypes' +import { GIFT_TYPES, GIFT_LABEL_MAP, emptyGiftCosts, DEFAULT_GIFT_COSTS } from '@/utils/giftTypes' import { getSlotResizeSpecs, resizeSlotToFile, probeResizedMeta, metaHasFileSize } from '@/composables/resizeImage' import { defaultPosterBundle, normalizePosterBundle, normalizePosterConfig, @@ -1451,8 +1486,10 @@ const danmakuFilter = ref('pending') const visitStatsLoading = ref(false) const visitListLoading = ref(false) const giftStatsLoading = ref(false) +const giftListLoading = ref(false) const giftCostsSaving = ref(false) const giftTypeList = GIFT_TYPES +const giftList = ref([]) const giftStats = reactive({ total: 0, counts: Object.fromEntries(GIFT_TYPES.map((g) => [g.key, 0])), @@ -2261,6 +2298,39 @@ async function loadGiftStats() { } } +const giftListColumns = [ + { title: '姓名', dataIndex: 'name', key: 'name', width: 120 }, + { title: '礼物', dataIndex: 'gift_type', key: 'gift_type', width: 120 }, + { title: '消耗', dataIndex: 'cost', key: 'cost', width: 90 }, + { title: '时间', dataIndex: 'created_at', key: 'created_at', width: 170 }, + { title: '操作', key: 'actions', width: 90 }, +] +const giftTypeLabel = (key) => GIFT_LABEL_MAP[key] || key || '—' + +async function loadGiftList() { + giftListLoading.value = true + try { + const res = await getGiftList() + const data = res.data || {} + giftList.value = Array.isArray(data.list) ? data.list : (Array.isArray(data) ? data : []) + } catch (e) { + giftList.value = [] + message.error(e?.message || '加载礼物明细失败') + } finally { + giftListLoading.value = false + } +} + +async function onDeleteGift(record) { + try { + await deleteGift(record.id) + message.success('已删除') + await Promise.all([loadGiftList(), loadGiftStats()]) + } catch (e) { + message.error(e?.message || '删除失败') + } +} + async function loadVisitStats() { visitStatsLoading.value = true try { @@ -2330,7 +2400,7 @@ async function onTabActivate(tab) { return } if (tab === 'gifts') { - await loadGiftStats() + await Promise.all([loadGiftStats(), loadGiftList()]) return } if (tab === 'visits') { diff --git a/vite-tailwindcss/src/views/index/index.vue b/vite-tailwindcss/src/views/index/index.vue index 7a44ae0..9386da5 100644 --- a/vite-tailwindcss/src/views/index/index.vue +++ b/vite-tailwindcss/src/views/index/index.vue @@ -1,6 +1,48 @@