2026-01-14 20:18:35 +08:00
|
|
|
{% extends "base.html" %}
|
|
|
|
|
|
|
|
|
|
{% block title %}全员充值记录 - 管理后台{% endblock %}
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
|
|
|
|
<div class="flex-1 overflow-y-auto p-8 relative">
|
|
|
|
|
<div class="max-w-7xl mx-auto space-y-8">
|
|
|
|
|
<!-- 头部 -->
|
|
|
|
|
<div class="flex items-center justify-between">
|
|
|
|
|
<div class="space-y-1">
|
|
|
|
|
<h1 class="text-3xl font-black text-slate-900 tracking-tight">全员充值记录</h1>
|
|
|
|
|
<p class="text-slate-500 font-bold text-sm flex items-center gap-2">
|
|
|
|
|
<i data-lucide="shield-check" class="w-4 h-4"></i>
|
|
|
|
|
管理和查询系统内所有用户的充值情况
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex gap-4">
|
|
|
|
|
<div class="relative">
|
2026-02-08 20:39:35 +08:00
|
|
|
<input type="text" id="orderSearch" placeholder="搜索手机号/订单号..."
|
|
|
|
|
class="pl-10 pr-4 py-2 bg-white border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-indigo-500 outline-none transition-all w-64">
|
2026-01-14 20:18:35 +08:00
|
|
|
<i data-lucide="search" class="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-slate-400"></i>
|
|
|
|
|
</div>
|
2026-02-08 20:39:35 +08:00
|
|
|
<button onclick="loadOrders()"
|
|
|
|
|
class="w-10 h-10 bg-white border border-slate-200 rounded-xl flex items-center justify-center text-slate-500 hover:text-indigo-600 transition-colors">
|
2026-01-14 20:18:35 +08:00
|
|
|
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 记录列表 -->
|
2026-02-08 20:39:35 +08:00
|
|
|
<div
|
|
|
|
|
class="bg-white/70 backdrop-blur-xl rounded-[2.5rem] border border-slate-200/50 shadow-2xl overflow-hidden">
|
2026-01-14 20:18:35 +08:00
|
|
|
<div class="overflow-x-auto">
|
|
|
|
|
<table class="w-full text-left border-collapse">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr class="border-b border-slate-100 bg-slate-50/50">
|
2026-02-08 20:39:35 +08:00
|
|
|
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest">用户信息
|
|
|
|
|
</th>
|
|
|
|
|
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest">订单详情
|
|
|
|
|
</th>
|
|
|
|
|
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest">积分/金额
|
|
|
|
|
</th>
|
|
|
|
|
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest">状态
|
|
|
|
|
</th>
|
|
|
|
|
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest">时间
|
|
|
|
|
</th>
|
|
|
|
|
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest">操作
|
|
|
|
|
</th>
|
2026-01-14 20:18:35 +08:00
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody id="orderList" class="divide-y divide-slate-100">
|
|
|
|
|
<tr>
|
2026-02-08 20:39:35 +08:00
|
|
|
<td colspan="6" class="px-8 py-20 text-center">
|
2026-01-14 20:18:35 +08:00
|
|
|
<div class="flex flex-col items-center gap-4 animate-pulse">
|
|
|
|
|
<i data-lucide="loader-2" class="w-8 h-8 text-indigo-500 animate-spin"></i>
|
|
|
|
|
<p class="text-slate-400 font-bold">正在获取记录...</p>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
|
|
{% block scripts %}
|
|
|
|
|
<script>
|
|
|
|
|
let allOrders = [];
|
|
|
|
|
|
|
|
|
|
async function loadOrders() {
|
|
|
|
|
try {
|
|
|
|
|
const r = await fetch('/api/admin/orders');
|
|
|
|
|
const d = await r.json();
|
|
|
|
|
allOrders = d.orders || [];
|
|
|
|
|
renderOrders(allOrders);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
showToast('加载失败: ' + e.message, 'error');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderOrders(orders) {
|
|
|
|
|
const list = document.getElementById('orderList');
|
|
|
|
|
if (orders.length === 0) {
|
2026-02-08 20:39:35 +08:00
|
|
|
renderEmptyState();
|
2026-01-14 20:18:35 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list.innerHTML = orders.map(o => `
|
|
|
|
|
<tr class="hover:bg-slate-50/50 transition-colors group">
|
|
|
|
|
<td class="px-8 py-5">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<div class="w-10 h-10 bg-indigo-50 text-indigo-600 rounded-xl flex items-center justify-center font-black text-xs">
|
|
|
|
|
${o.user_phone.slice(-4)}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col">
|
|
|
|
|
<span class="text-sm font-bold text-slate-700">${o.user_phone}</span>
|
|
|
|
|
<span class="text-[10px] text-slate-400">UID: ${o.id}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td class="px-8 py-5">
|
|
|
|
|
<div class="flex flex-col">
|
|
|
|
|
<span class="text-xs font-bold text-slate-600">${o.out_trade_no}</span>
|
|
|
|
|
<span class="text-[10px] text-slate-400 font-mono">Ali: ${o.trade_no || '-'}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td class="px-8 py-5">
|
|
|
|
|
<div class="flex flex-col">
|
|
|
|
|
<div class="flex items-center gap-1">
|
|
|
|
|
<i data-lucide="zap" class="w-3 h-3 text-amber-500"></i>
|
|
|
|
|
<span class="text-sm font-black text-slate-900">+${o.points}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="text-xs font-bold text-slate-400">¥${o.amount}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td class="px-8 py-5">
|
2026-02-08 20:39:35 +08:00
|
|
|
${o.status === 'PAID'
|
|
|
|
|
? '<span class="px-3 py-1 bg-emerald-50 text-emerald-600 text-[10px] font-black rounded-lg border border-emerald-100">已完成</span>'
|
|
|
|
|
: o.status === 'PENDING'
|
|
|
|
|
? '<span class="px-3 py-1 bg-amber-50 text-amber-600 text-[10px] font-black rounded-lg border border-amber-100">待支付</span>'
|
|
|
|
|
: '<span class="px-3 py-1 bg-slate-50 text-slate-400 text-[10px] font-black rounded-lg border border-slate-100">已取消</span>'
|
|
|
|
|
}
|
2026-01-14 20:18:35 +08:00
|
|
|
</td>
|
2026-02-08 20:39:35 +08:00
|
|
|
<td class="px-8 py-5 text-right">
|
2026-01-14 20:18:35 +08:00
|
|
|
<div class="flex flex-col">
|
|
|
|
|
<span class="text-[10px] font-bold text-slate-500">创建: ${o.created_at}</span>
|
|
|
|
|
<span class="text-[10px] font-bold text-emerald-500">${o.paid_at ? '完成: ' + o.paid_at : ''}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
2026-02-08 20:39:35 +08:00
|
|
|
<td class="px-8 py-5">
|
|
|
|
|
<a href="/admin/orders/${o.id}" class="w-8 h-8 bg-slate-50 text-slate-400 hover:bg-indigo-50 hover:text-indigo-600 rounded-lg flex items-center justify-center transition-all">
|
|
|
|
|
<i data-lucide="eye" class="w-4 h-4"></i>
|
|
|
|
|
</a>
|
|
|
|
|
</td>
|
2026-01-14 20:18:35 +08:00
|
|
|
</tr>
|
|
|
|
|
`).join('');
|
|
|
|
|
lucide.createIcons();
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 20:39:35 +08:00
|
|
|
function renderEmptyState() {
|
|
|
|
|
const list = document.getElementById('orderList');
|
|
|
|
|
list.innerHTML = `
|
|
|
|
|
<tr>
|
|
|
|
|
<td colspan="6" class="px-8 py-20 text-center">
|
|
|
|
|
<div class="flex flex-col items-center gap-4 opacity-20">
|
|
|
|
|
<i data-lucide="inbox" class="w-16 h-16"></i>
|
|
|
|
|
<p class="font-black text-xl">暂无记录</p>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
`;
|
|
|
|
|
lucide.createIcons();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 20:18:35 +08:00
|
|
|
document.getElementById('orderSearch').oninput = (e) => {
|
|
|
|
|
const val = e.target.value.toLowerCase();
|
2026-02-08 20:39:35 +08:00
|
|
|
const filtered = allOrders.filter(o =>
|
|
|
|
|
o.user_phone.includes(val) ||
|
2026-01-14 20:18:35 +08:00
|
|
|
o.out_trade_no.toLowerCase().includes(val)
|
|
|
|
|
);
|
|
|
|
|
renderOrders(filtered);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
loadOrders();
|
|
|
|
|
</script>
|
2026-02-08 20:39:35 +08:00
|
|
|
{% endblock %}
|