Files
lunar-mini/server/web/static/js/pages/Charts.js
T
gouki deb32f8fab
Build and Publish Server / build (push) Successful in 4m30s
feat(server): 商业化支付与订单系统 + Harness 改进
- 新增商业化模块:Stripe/Binance Pay 支付、邮箱登录、订单管理
- 新增数据模型:ReportProduct, ReportEntitlement, ReportSnapshot, PaymentEvent, EmailLoginCode
- 新增 API:/api/commerce/checkout, /api/commerce/webhooks/*, /api/commerce/orders/*
- 新增管理后台:订单列表、统计图表、统一 AdminHeader 组件
- 新增中间件测试:RateLimit, Auth, CORS 共 7 个测试用例
- 新增 AGENTS.md 项目代理指令文件
- 新增 REMINDER.md 商业化功能开发规范
- 修复 JWT 解析:添加 WithValidMethods 限制 HS256
- 修复 GetPayStatus:增加用户权限校验
- 更新 .gitignore 和 README.md
2026-09-19 18:57:23 +00:00

58 lines
3.7 KiB
JavaScript

import { onMounted, ref } from 'vue';
import { adminHeader } from './AdminHeader.js';
export default {
setup() {
const records = ref([]);
const total = ref(0);
const loading = ref(true);
const error = ref('');
const search = ref('');
const load = async () => {
loading.value = true;
error.value = '';
try {
const params = new URLSearchParams({ page: '1', pageSize: '100' });
if (search.value) params.set('search', search.value);
const response = await fetch('/admin/api/charts?' + params.toString(), { credentials: 'same-origin' });
if (!response.ok) throw new Error('加载排盘记录失败');
const payload = await response.json();
records.value = payload.data.list || [];
total.value = payload.data.total || 0;
} catch (reason) {
error.value = reason instanceof Error ? reason.message : '加载排盘记录失败';
} finally {
loading.value = false;
}
};
onMounted(load);
return { records, total, loading, error, search, load };
},
template: `
<div class="min-h-screen bg-gray-100">
${adminHeader('charts')}
<main class="max-w-7xl mx-auto py-8 px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg">
<div class="p-5 border-b flex flex-col sm:flex-row gap-3 sm:items-center sm:justify-between">
<div><h2 class="text-lg font-medium">排盘记录</h2><p class="text-xs text-gray-500 mt-1">共 {{ total }} 次排盘,保存免费排盘快照,付费报告另行关联</p></div>
<div class="flex gap-2"><input v-model="search" @keyup.enter="load" class="border rounded px-3 py-2 text-sm" placeholder="报告编号 / 姓名 / 城市" /><button @click="load" class="bg-red-700 text-white rounded px-4 py-2 text-sm">查询</button></div>
</div>
<div v-if="error" class="m-5 p-3 bg-red-50 text-red-700 text-sm">{{ error }}</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50"><tr><th class="px-4 py-3 text-left text-xs text-gray-500">报告编号</th><th class="px-4 py-3 text-left text-xs text-gray-500">称呼</th><th class="px-4 py-3 text-left text-xs text-gray-500">出生信息</th><th class="px-4 py-3 text-left text-xs text-gray-500">城市</th><th class="px-4 py-3 text-left text-xs text-gray-500">记录时间</th></tr></thead>
<tbody class="divide-y divide-gray-100">
<tr v-if="loading"><td colspan="5" class="p-10 text-center text-sm text-gray-500">正在加载...</td></tr>
<tr v-else-if="records.length === 0"><td colspan="5" class="p-10 text-center text-sm text-gray-500">暂无排盘记录</td></tr>
<tr v-for="record in records" :key="record.id" class="hover:bg-gray-50"><td class="px-4 py-4 text-xs font-medium">{{ record.reportId }}</td><td class="px-4 py-4 text-sm">{{ record.name || '-' }}</td><td class="px-4 py-4 text-sm">{{ record.birthDate }} {{ record.birthTime }} / {{ record.gender }}</td><td class="px-4 py-4 text-sm">{{ record.city }}</td><td class="px-4 py-4 text-xs text-gray-500">{{ new Date(record.createdAt).toLocaleString('zh-CN', { hour12: false }) }}</td></tr>
</tbody>
</table>
</div>
</div>
</main>
</div>
`,
};