Files
image2api/frontend/src/views/InvitesAdminView.vue
T
chiyiandDevin 602664c122 style(ui): 全站清除紫色系,统一 Memphis 蜡笔配色
- Logo 渐变从粉紫改为橙/粉/蓝蜡笔色,快门圆点改橙色
- 批量替换 accent:violet→orange、fuchsia→rose、indigo→sky、purple→orange,
  十六进制与 rgb 字面量同步换算为 Tailwind 对应色
- 修复类名合并冲突:管理员筛选 pill 改 fp-orange、会员号改 fp-pink(新增),
  style.css 中去重 fp-rose/fp-orange 并补 fp-pink 的浅色模式变体
- 选区色、标签输入框、筛选 pill、图表、滑块等所有紫色残留全部归位

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-08 17:15:17 +08:00

103 lines
4.9 KiB
Vue

<script setup>
// Admin invite log — global view of every invite relationship across accounts.
import { ref, onMounted } from 'vue'
import { api } from '../api'
import { fmtIso } from '../utils/format'
import Icon from '../components/Icon.vue'
const items = ref([])
const stats = ref({ total: 0, completed: 0, pending: 0, reward_paid: 0 })
const loading = ref(false)
async function load() {
loading.value = true
const r = await api('/invites')
loading.value = false
if (r.ok) { items.value = r.data?.data || []; stats.value = r.data?.stats || stats.value }
}
onMounted(load)
</script>
<template>
<section class="space-y-4">
<!-- KPI strip — same shape as the LogsView so the admin shell stays
consistent. /invites already returns the stats payload. -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-3">
<div class="card p-4">
<div class="text-[11px] uppercase tracking-wider text-white/45">总邀请</div>
<div class="text-2xl font-semibold mt-1 tabular-nums">{{ stats.total }}</div>
</div>
<div class="card p-4">
<div class="text-[11px] uppercase tracking-wider text-emerald-300/80">已完成</div>
<div class="text-2xl font-semibold mt-1 tabular-nums text-emerald-300">{{ stats.completed }}</div>
</div>
<div class="card p-4">
<div class="text-[11px] uppercase tracking-wider text-amber-300/80">待生图</div>
<div class="text-2xl font-semibold mt-1 tabular-nums text-amber-300">{{ stats.pending }}</div>
</div>
<div class="card p-4">
<div class="text-[11px] uppercase tracking-wider text-rose-300/80">已发奖励</div>
<div class="text-2xl font-semibold mt-1 tabular-nums text-rose-300">{{ Number(stats.reward_paid || 0).toLocaleString('en-US') }}</div>
</div>
</div>
<div class="card overflow-hidden">
<div class="px-5 py-3 border-b border-white/[0.06] flex items-center justify-between">
<div class="text-xs text-white/55">全站邀请记录:谁邀请了谁、注册与完成时间、奖励状态。</div>
<button @click="load" class="btn-soft"><Icon name="refresh" class="w-3.5 h-3.5" /> 刷新</button>
</div>
<div v-if="loading && !items.length" class="text-center text-sm text-white/40 py-16">加载中…</div>
<div v-else-if="!items.length" class="text-center text-sm text-white/40 py-16">还没有邀请记录</div>
<table v-else class="w-full text-sm">
<colgroup>
<col />
<col />
<col class="w-24" />
<col class="w-44" />
<col class="w-44" />
<col class="w-28" />
</colgroup>
<thead>
<tr class="text-[10px] uppercase tracking-[0.2em] text-white/40 border-b border-white/[0.06]">
<th class="text-left px-5 py-3 font-medium">邀请人</th>
<th class="text-left px-3 py-3 font-medium">被邀请人</th>
<th class="text-right px-3 py-3 font-medium">奖励</th>
<th class="text-left px-3 py-3 font-medium">注册时间</th>
<th class="text-left px-3 py-3 font-medium">完成时间</th>
<th class="text-right px-5 py-3 font-medium">状态</th>
</tr>
</thead>
<tbody>
<tr v-for="(r, i) in items" :key="i"
class="border-b border-white/[0.04] hover:bg-white/[0.03] transition-colors">
<td class="px-5 py-3.5 align-middle font-medium text-white/90 truncate">{{ r.inviter }}</td>
<td class="px-3 py-3.5 align-middle text-white/75 truncate">{{ r.invitee }}</td>
<td class="px-3 py-3.5 align-middle text-right tabular-nums whitespace-nowrap"
:class="r.reward ? 'text-emerald-300' : 'text-white/25'">
{{ r.reward ? '+' + r.reward : '—' }}
</td>
<td class="px-3 py-3.5 align-middle text-xs text-white/55 tabular-nums whitespace-nowrap">
{{ r.registered_at ? fmtIso(r.registered_at) : '—' }}
</td>
<td class="px-3 py-3.5 align-middle text-xs text-white/55 tabular-nums whitespace-nowrap">
{{ r.completed_at ? fmtIso(r.completed_at) : '—' }}
</td>
<td class="px-5 py-3.5 align-middle text-right">
<span class="inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-medium ring-1"
:class="r.status === 'completed'
? 'bg-emerald-500/10 text-emerald-300 ring-emerald-400/30'
: 'bg-amber-500/10 text-amber-300 ring-amber-400/30'">
<span class="w-1.5 h-1.5 rounded-full"
:class="r.status === 'completed' ? 'bg-emerald-400' : 'bg-amber-400'"></span>
{{ r.status === 'completed' ? '已完成' : '待生图' }}
</span>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</template>