llmapi-v2 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +40 -0
- package/Dockerfile +17 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.js +98 -0
- package/dist/config.js.map +1 -0
- package/dist/converter/request.d.ts +6 -0
- package/dist/converter/request.js +184 -0
- package/dist/converter/request.js.map +1 -0
- package/dist/converter/response.d.ts +6 -0
- package/dist/converter/response.js +76 -0
- package/dist/converter/response.js.map +1 -0
- package/dist/converter/stream.d.ts +54 -0
- package/dist/converter/stream.js +318 -0
- package/dist/converter/stream.js.map +1 -0
- package/dist/converter/types.d.ts +239 -0
- package/dist/converter/types.js +6 -0
- package/dist/converter/types.js.map +1 -0
- package/dist/data/posts.d.ts +19 -0
- package/dist/data/posts.js +462 -0
- package/dist/data/posts.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +233 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/api-key-auth.d.ts +6 -0
- package/dist/middleware/api-key-auth.js +76 -0
- package/dist/middleware/api-key-auth.js.map +1 -0
- package/dist/middleware/quota-guard.d.ts +10 -0
- package/dist/middleware/quota-guard.js +27 -0
- package/dist/middleware/quota-guard.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +5 -0
- package/dist/middleware/rate-limiter.js +50 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +6 -0
- package/dist/middleware/request-logger.js +37 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/middleware/session-auth.d.ts +19 -0
- package/dist/middleware/session-auth.js +99 -0
- package/dist/middleware/session-auth.js.map +1 -0
- package/dist/providers/aliyun.d.ts +13 -0
- package/dist/providers/aliyun.js +20 -0
- package/dist/providers/aliyun.js.map +1 -0
- package/dist/providers/base-provider.d.ts +36 -0
- package/dist/providers/base-provider.js +133 -0
- package/dist/providers/base-provider.js.map +1 -0
- package/dist/providers/deepseek.d.ts +11 -0
- package/dist/providers/deepseek.js +18 -0
- package/dist/providers/deepseek.js.map +1 -0
- package/dist/providers/registry.d.ts +18 -0
- package/dist/providers/registry.js +98 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +17 -0
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/routes/admin.d.ts +1 -0
- package/dist/routes/admin.js +153 -0
- package/dist/routes/admin.js.map +1 -0
- package/dist/routes/auth.d.ts +2 -0
- package/dist/routes/auth.js +318 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/blog.d.ts +1 -0
- package/dist/routes/blog.js +29 -0
- package/dist/routes/blog.js.map +1 -0
- package/dist/routes/dashboard.d.ts +1 -0
- package/dist/routes/dashboard.js +184 -0
- package/dist/routes/dashboard.js.map +1 -0
- package/dist/routes/messages.d.ts +1 -0
- package/dist/routes/messages.js +309 -0
- package/dist/routes/messages.js.map +1 -0
- package/dist/routes/models.d.ts +1 -0
- package/dist/routes/models.js +39 -0
- package/dist/routes/models.js.map +1 -0
- package/dist/routes/payment.d.ts +1 -0
- package/dist/routes/payment.js +150 -0
- package/dist/routes/payment.js.map +1 -0
- package/dist/routes/sitemap.d.ts +1 -0
- package/dist/routes/sitemap.js +38 -0
- package/dist/routes/sitemap.js.map +1 -0
- package/dist/services/alipay.d.ts +27 -0
- package/dist/services/alipay.js +106 -0
- package/dist/services/alipay.js.map +1 -0
- package/dist/services/database.d.ts +4 -0
- package/dist/services/database.js +170 -0
- package/dist/services/database.js.map +1 -0
- package/dist/services/health-checker.d.ts +13 -0
- package/dist/services/health-checker.js +95 -0
- package/dist/services/health-checker.js.map +1 -0
- package/dist/services/mailer.d.ts +3 -0
- package/dist/services/mailer.js +91 -0
- package/dist/services/mailer.js.map +1 -0
- package/dist/services/metrics.d.ts +56 -0
- package/dist/services/metrics.js +94 -0
- package/dist/services/metrics.js.map +1 -0
- package/dist/services/remote-control.d.ts +20 -0
- package/dist/services/remote-control.js +209 -0
- package/dist/services/remote-control.js.map +1 -0
- package/dist/services/remote-ws.d.ts +5 -0
- package/dist/services/remote-ws.js +143 -0
- package/dist/services/remote-ws.js.map +1 -0
- package/dist/services/usage.d.ts +13 -0
- package/dist/services/usage.js +39 -0
- package/dist/services/usage.js.map +1 -0
- package/dist/utils/errors.d.ts +27 -0
- package/dist/utils/errors.js +48 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +14 -0
- package/dist/utils/logger.js.map +1 -0
- package/docker-compose.yml +19 -0
- package/package.json +39 -0
- package/public/robots.txt +8 -0
- package/src/config.ts +140 -0
- package/src/converter/request.ts +207 -0
- package/src/converter/response.ts +85 -0
- package/src/converter/stream.ts +373 -0
- package/src/converter/types.ts +257 -0
- package/src/data/posts.ts +474 -0
- package/src/index.ts +219 -0
- package/src/middleware/api-key-auth.ts +82 -0
- package/src/middleware/quota-guard.ts +28 -0
- package/src/middleware/rate-limiter.ts +61 -0
- package/src/middleware/request-logger.ts +36 -0
- package/src/middleware/session-auth.ts +91 -0
- package/src/providers/aliyun.ts +16 -0
- package/src/providers/base-provider.ts +148 -0
- package/src/providers/deepseek.ts +14 -0
- package/src/providers/registry.ts +111 -0
- package/src/providers/types.ts +26 -0
- package/src/routes/admin.ts +169 -0
- package/src/routes/auth.ts +369 -0
- package/src/routes/blog.ts +28 -0
- package/src/routes/dashboard.ts +208 -0
- package/src/routes/messages.ts +346 -0
- package/src/routes/models.ts +37 -0
- package/src/routes/payment.ts +189 -0
- package/src/routes/sitemap.ts +40 -0
- package/src/services/alipay.ts +116 -0
- package/src/services/database.ts +187 -0
- package/src/services/health-checker.ts +115 -0
- package/src/services/mailer.ts +90 -0
- package/src/services/metrics.ts +104 -0
- package/src/services/remote-control.ts +226 -0
- package/src/services/remote-ws.ts +145 -0
- package/src/services/usage.ts +57 -0
- package/src/types/express.d.ts +46 -0
- package/src/utils/errors.ts +44 -0
- package/src/utils/logger.ts +8 -0
- package/tsconfig.json +17 -0
- package/views/pages/404.ejs +14 -0
- package/views/pages/admin.ejs +307 -0
- package/views/pages/blog-post.ejs +378 -0
- package/views/pages/blog.ejs +148 -0
- package/views/pages/dashboard.ejs +441 -0
- package/views/pages/docs.ejs +807 -0
- package/views/pages/index.ejs +416 -0
- package/views/pages/login.ejs +170 -0
- package/views/pages/orders.ejs +111 -0
- package/views/pages/pricing.ejs +379 -0
- package/views/pages/register.ejs +397 -0
- package/views/pages/remote.ejs +334 -0
- package/views/pages/settings.ejs +373 -0
- package/views/partials/header.ejs +70 -0
- package/views/partials/nav.ejs +140 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<%- include('../partials/header', { pageTitle: '我的订单' }) %>
|
|
2
|
+
<%- include('../partials/nav') %>
|
|
3
|
+
|
|
4
|
+
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
5
|
+
|
|
6
|
+
<!-- 页面标题 -->
|
|
7
|
+
<div class="mb-8">
|
|
8
|
+
<h1 class="text-2xl font-bold text-claude-dark">我的订单</h1>
|
|
9
|
+
<p class="text-sm text-gray-500 mt-1">查看所有订单记录与支付状态</p>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<!-- 订单列表 -->
|
|
13
|
+
<div id="orderList">
|
|
14
|
+
<div class="text-center py-16 text-gray-400">加载中...</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
function fmtMoney(n) {
|
|
21
|
+
if (n == null) return '--';
|
|
22
|
+
return '¥' + Number(n).toFixed(2);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function fmtDate(d) {
|
|
26
|
+
if (!d) return '--';
|
|
27
|
+
return new Date(d).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function escHtml(s) {
|
|
31
|
+
if (!s) return '';
|
|
32
|
+
const d = document.createElement('div');
|
|
33
|
+
d.textContent = s;
|
|
34
|
+
return d.innerHTML;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function statusBadge(status) {
|
|
38
|
+
const map = {
|
|
39
|
+
pending: { label: '待支付', cls: 'bg-yellow-100 text-yellow-700' },
|
|
40
|
+
paid: { label: '已支付', cls: 'bg-green-100 text-green-700' },
|
|
41
|
+
cancelled: { label: '已取消', cls: 'bg-gray-100 text-gray-500' },
|
|
42
|
+
refunded: { label: '已退款', cls: 'bg-red-100 text-red-600' },
|
|
43
|
+
expired: { label: '已过期', cls: 'bg-gray-100 text-gray-400' },
|
|
44
|
+
};
|
|
45
|
+
const s = map[status] || { label: status || '未知', cls: 'bg-gray-100 text-gray-500' };
|
|
46
|
+
return `<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${s.cls}">${s.label}</span>`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function planLabel(p) {
|
|
50
|
+
const map = { free: '免费版', basic: '基础版', pro: '专业版', enterprise: '企业版' };
|
|
51
|
+
return map[p] || p || '--';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function loadOrders() {
|
|
55
|
+
const container = document.getElementById('orderList');
|
|
56
|
+
try {
|
|
57
|
+
const res = await fetch('/api/payment/orders', { credentials: 'same-origin' });
|
|
58
|
+
if (!res.ok) throw new Error('请求失败');
|
|
59
|
+
const data = await res.json();
|
|
60
|
+
const orders = data.data || data || [];
|
|
61
|
+
|
|
62
|
+
if (!orders.length) {
|
|
63
|
+
container.innerHTML = `
|
|
64
|
+
<div class="text-center py-20">
|
|
65
|
+
<svg class="w-16 h-16 mx-auto text-gray-300 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
66
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
|
|
67
|
+
</svg>
|
|
68
|
+
<p class="text-gray-500 mb-4">暂无订单记录</p>
|
|
69
|
+
<a href="/pricing" class="inline-flex items-center px-5 py-2.5 text-sm font-medium text-white bg-claude-orange rounded-lg hover:bg-opacity-90 transition-all shadow-sm">
|
|
70
|
+
查看套餐定价 →
|
|
71
|
+
</a>
|
|
72
|
+
</div>
|
|
73
|
+
`;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
container.innerHTML = '<div class="space-y-4">' + orders.map(o => `
|
|
78
|
+
<div class="bg-white rounded-xl border border-gray-100 p-5 shadow-sm hover:shadow transition-shadow">
|
|
79
|
+
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
|
80
|
+
<div class="flex-1 min-w-0">
|
|
81
|
+
<div class="flex items-center space-x-3 mb-2">
|
|
82
|
+
<h3 class="text-base font-semibold text-claude-dark">${escHtml(planLabel(o.plan))}</h3>
|
|
83
|
+
${statusBadge(o.status)}
|
|
84
|
+
</div>
|
|
85
|
+
<div class="flex flex-wrap gap-x-6 gap-y-1 text-sm text-gray-500">
|
|
86
|
+
<span>订单号:<code class="text-xs font-mono bg-gray-50 px-1.5 py-0.5 rounded">${escHtml(o.orderNo || o.id || o._id)}</code></span>
|
|
87
|
+
<span>创建时间:${fmtDate(o.createdAt)}</span>
|
|
88
|
+
${o.paidAt ? `<span>支付时间:${fmtDate(o.paidAt)}</span>` : ''}
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="text-right flex-shrink-0">
|
|
92
|
+
<div class="text-xl font-bold text-claude-dark">${fmtMoney(o.amount)}</div>
|
|
93
|
+
${o.status === 'pending' ? `
|
|
94
|
+
<a href="${escHtml(o.payUrl || '#')}" class="inline-block mt-2 px-4 py-1.5 text-xs font-medium text-white bg-claude-orange rounded-lg hover:bg-opacity-90 transition-all">去支付</a>
|
|
95
|
+
` : ''}
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
`).join('') + '</div>';
|
|
100
|
+
|
|
101
|
+
} catch (e) {
|
|
102
|
+
console.error('加载订单失败:', e);
|
|
103
|
+
container.innerHTML = '<div class="text-center py-16 text-red-400">加载失败,请刷新重试</div>';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
loadOrders();
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
</body>
|
|
111
|
+
</html>
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
<%- include('../partials/header') %>
|
|
2
|
+
<%- include('../partials/nav') %>
|
|
3
|
+
|
|
4
|
+
<main class="min-h-[calc(100vh-4rem)] py-12 px-4">
|
|
5
|
+
<div class="max-w-6xl mx-auto">
|
|
6
|
+
<!-- Page Header -->
|
|
7
|
+
<div class="text-center mb-12">
|
|
8
|
+
<h1 class="text-3xl sm:text-4xl font-bold text-claude-dark">选择适合您的套餐</h1>
|
|
9
|
+
<p class="mt-3 text-lg text-claude-dark/60 max-w-2xl mx-auto">灵活的定价方案,满足从个人开发者到企业团队的各种需求</p>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<!-- Pricing Grid -->
|
|
13
|
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
14
|
+
|
|
15
|
+
<!-- Free Plan -->
|
|
16
|
+
<div class="bg-white rounded-2xl shadow-sm border border-claude-dark/5 p-6 flex flex-col">
|
|
17
|
+
<div class="mb-6">
|
|
18
|
+
<h3 class="text-lg font-semibold text-claude-dark">Free</h3>
|
|
19
|
+
<p class="text-sm text-claude-dark/50 mt-1">体验入门</p>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="mb-6">
|
|
22
|
+
<span class="text-4xl font-bold text-claude-dark">0</span>
|
|
23
|
+
<span class="text-claude-dark/50 text-sm">元/月</span>
|
|
24
|
+
</div>
|
|
25
|
+
<ul class="space-y-3 mb-8 flex-1 text-sm text-claude-dark/70">
|
|
26
|
+
<li class="flex items-start">
|
|
27
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
28
|
+
<span>50K tokens / 月</span>
|
|
29
|
+
</li>
|
|
30
|
+
<li class="flex items-start">
|
|
31
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
32
|
+
<span>10 次/分钟 速率限制</span>
|
|
33
|
+
</li>
|
|
34
|
+
<li class="flex items-start">
|
|
35
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
36
|
+
<span>1 个 API Key</span>
|
|
37
|
+
</li>
|
|
38
|
+
<li class="flex items-start">
|
|
39
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
40
|
+
<span>基础模型支持</span>
|
|
41
|
+
</li>
|
|
42
|
+
<li class="flex items-start">
|
|
43
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
44
|
+
<span>社区支持</span>
|
|
45
|
+
</li>
|
|
46
|
+
</ul>
|
|
47
|
+
<% if (typeof viewUser !== 'undefined' && viewUser) { %>
|
|
48
|
+
<button disabled class="w-full py-2.5 px-4 bg-claude-dark/5 text-claude-dark/40 font-medium rounded-lg text-sm cursor-not-allowed">当前套餐</button>
|
|
49
|
+
<% } else { %>
|
|
50
|
+
<a href="/register" class="block w-full py-2.5 px-4 bg-claude-dark/5 text-claude-dark font-medium rounded-lg hover:bg-claude-dark/10 transition-colors text-sm text-center">选择套餐</a>
|
|
51
|
+
<% } %>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<!-- Starter Plan -->
|
|
55
|
+
<div class="bg-white rounded-2xl shadow-sm border border-claude-dark/5 p-6 flex flex-col">
|
|
56
|
+
<div class="mb-6">
|
|
57
|
+
<h3 class="text-lg font-semibold text-claude-dark">Starter</h3>
|
|
58
|
+
<p class="text-sm text-claude-dark/50 mt-1">个人开发者</p>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="mb-6">
|
|
61
|
+
<span class="text-4xl font-bold text-claude-dark">9</span>
|
|
62
|
+
<span class="text-claude-dark/50 text-sm">元/月</span>
|
|
63
|
+
</div>
|
|
64
|
+
<ul class="space-y-3 mb-8 flex-1 text-sm text-claude-dark/70">
|
|
65
|
+
<li class="flex items-start">
|
|
66
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
67
|
+
<span>2M tokens / 月</span>
|
|
68
|
+
</li>
|
|
69
|
+
<li class="flex items-start">
|
|
70
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
71
|
+
<span>30 次/分钟 速率限制</span>
|
|
72
|
+
</li>
|
|
73
|
+
<li class="flex items-start">
|
|
74
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
75
|
+
<span>3 个 API Key</span>
|
|
76
|
+
</li>
|
|
77
|
+
<li class="flex items-start">
|
|
78
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
79
|
+
<span>全部模型支持</span>
|
|
80
|
+
</li>
|
|
81
|
+
<li class="flex items-start">
|
|
82
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
83
|
+
<span>邮件支持</span>
|
|
84
|
+
</li>
|
|
85
|
+
</ul>
|
|
86
|
+
<% if (typeof viewUser !== 'undefined' && viewUser) { %>
|
|
87
|
+
<button onclick="handleSubscribe('starter')" class="w-full py-2.5 px-4 bg-claude-orange text-white font-medium rounded-lg hover:bg-claude-orange/90 transition-colors text-sm">订阅</button>
|
|
88
|
+
<% } else { %>
|
|
89
|
+
<a href="/register" class="block w-full py-2.5 px-4 bg-claude-orange text-white font-medium rounded-lg hover:bg-claude-orange/90 transition-colors text-sm text-center">选择套餐</a>
|
|
90
|
+
<% } %>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<!-- Pro Plan (Recommended) -->
|
|
94
|
+
<div class="bg-white rounded-2xl shadow-md border-2 border-claude-orange p-6 flex flex-col relative">
|
|
95
|
+
<div class="absolute -top-3 left-1/2 -translate-x-1/2">
|
|
96
|
+
<span class="bg-claude-orange text-white text-xs font-semibold px-3 py-1 rounded-full">推荐</span>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="mb-6">
|
|
99
|
+
<h3 class="text-lg font-semibold text-claude-dark">Pro</h3>
|
|
100
|
+
<p class="text-sm text-claude-dark/50 mt-1">专业开发者</p>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="mb-6">
|
|
103
|
+
<span class="text-4xl font-bold text-claude-dark">29</span>
|
|
104
|
+
<span class="text-claude-dark/50 text-sm">元/月</span>
|
|
105
|
+
</div>
|
|
106
|
+
<ul class="space-y-3 mb-8 flex-1 text-sm text-claude-dark/70">
|
|
107
|
+
<li class="flex items-start">
|
|
108
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
109
|
+
<span>10M tokens / 月</span>
|
|
110
|
+
</li>
|
|
111
|
+
<li class="flex items-start">
|
|
112
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
113
|
+
<span>60 次/分钟 速率限制</span>
|
|
114
|
+
</li>
|
|
115
|
+
<li class="flex items-start">
|
|
116
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
117
|
+
<span>5 个 API Key</span>
|
|
118
|
+
</li>
|
|
119
|
+
<li class="flex items-start">
|
|
120
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
121
|
+
<span>全部模型 + 优先路由</span>
|
|
122
|
+
</li>
|
|
123
|
+
<li class="flex items-start">
|
|
124
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
125
|
+
<span>优先技术支持</span>
|
|
126
|
+
</li>
|
|
127
|
+
<li class="flex items-start">
|
|
128
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
129
|
+
<span>用量统计分析</span>
|
|
130
|
+
</li>
|
|
131
|
+
</ul>
|
|
132
|
+
<% if (typeof viewUser !== 'undefined' && viewUser) { %>
|
|
133
|
+
<button onclick="handleSubscribe('pro')" class="w-full py-2.5 px-4 bg-claude-orange text-white font-medium rounded-lg hover:bg-claude-orange/90 transition-colors text-sm shadow-sm">订阅</button>
|
|
134
|
+
<% } else { %>
|
|
135
|
+
<a href="/register" class="block w-full py-2.5 px-4 bg-claude-orange text-white font-medium rounded-lg hover:bg-claude-orange/90 transition-colors text-sm text-center shadow-sm">选择套餐</a>
|
|
136
|
+
<% } %>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<!-- Unlimited Plan -->
|
|
140
|
+
<div class="bg-white rounded-2xl shadow-sm border border-claude-dark/5 p-6 flex flex-col">
|
|
141
|
+
<div class="mb-6">
|
|
142
|
+
<h3 class="text-lg font-semibold text-claude-dark">Team</h3>
|
|
143
|
+
<p class="text-sm text-claude-dark/50 mt-1">团队 / 企业</p>
|
|
144
|
+
</div>
|
|
145
|
+
<div class="mb-6">
|
|
146
|
+
<span class="text-4xl font-bold text-claude-dark">99</span>
|
|
147
|
+
<span class="text-claude-dark/50 text-sm">元/月</span>
|
|
148
|
+
</div>
|
|
149
|
+
<ul class="space-y-3 mb-8 flex-1 text-sm text-claude-dark/70">
|
|
150
|
+
<li class="flex items-start">
|
|
151
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
152
|
+
<span>50M tokens / 月</span>
|
|
153
|
+
</li>
|
|
154
|
+
<li class="flex items-start">
|
|
155
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
156
|
+
<span>120 次/分钟 速率限制</span>
|
|
157
|
+
</li>
|
|
158
|
+
<li class="flex items-start">
|
|
159
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
160
|
+
<span>10 个 API Key</span>
|
|
161
|
+
</li>
|
|
162
|
+
<li class="flex items-start">
|
|
163
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
164
|
+
<span>全部模型 + 专属路由</span>
|
|
165
|
+
</li>
|
|
166
|
+
<li class="flex items-start">
|
|
167
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
168
|
+
<span>1 对 1 专属支持</span>
|
|
169
|
+
</li>
|
|
170
|
+
<li class="flex items-start">
|
|
171
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
172
|
+
<span>SLA 可用性保障</span>
|
|
173
|
+
</li>
|
|
174
|
+
<li class="flex items-start">
|
|
175
|
+
<svg class="w-5 h-5 text-green-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
|
176
|
+
<span>高级用量分析</span>
|
|
177
|
+
</li>
|
|
178
|
+
</ul>
|
|
179
|
+
<% if (typeof viewUser !== 'undefined' && viewUser) { %>
|
|
180
|
+
<button onclick="handleSubscribe('unlimited')" class="w-full py-2.5 px-4 bg-claude-orange text-white font-medium rounded-lg hover:bg-claude-orange/90 transition-colors text-sm">订阅</button>
|
|
181
|
+
<% } else { %>
|
|
182
|
+
<a href="/register" class="block w-full py-2.5 px-4 bg-claude-orange text-white font-medium rounded-lg hover:bg-claude-orange/90 transition-colors text-sm text-center">选择套餐</a>
|
|
183
|
+
<% } %>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<div class="text-center mt-8">
|
|
189
|
+
<p class="text-sm text-claude-dark/50">1 typical Claude Code conversation uses ~15K tokens</p>
|
|
190
|
+
<p class="text-sm text-claude-dark/50 mt-1">Claude Code Max costs $200/month for similar usage. Our Pro plan is $29.</p>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<!-- FAQ Section -->
|
|
194
|
+
<div class="mt-16 max-w-3xl mx-auto">
|
|
195
|
+
<h2 class="text-2xl font-bold text-claude-dark text-center mb-8">常见问题</h2>
|
|
196
|
+
<div class="space-y-4">
|
|
197
|
+
<div class="bg-white rounded-xl border border-claude-dark/5 p-5">
|
|
198
|
+
<h3 class="font-medium text-claude-dark">什么是 tokens?</h3>
|
|
199
|
+
<p class="mt-2 text-sm text-claude-dark/60">Tokens 是 AI 模型处理文本的基本单位。中文大约每个字对应 1-2 个 token,英文每个单词约 1-3 个 token。每月额度包含输入和输出的总 token 数。</p>
|
|
200
|
+
</div>
|
|
201
|
+
<div class="bg-white rounded-xl border border-claude-dark/5 p-5">
|
|
202
|
+
<h3 class="font-medium text-claude-dark">可以随时切换套餐吗?</h3>
|
|
203
|
+
<p class="mt-2 text-sm text-claude-dark/60">可以。升级套餐会立即生效,当月额度即时更新。降级将在当前计费周期结束后生效。</p>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="bg-white rounded-xl border border-claude-dark/5 p-5">
|
|
206
|
+
<h3 class="font-medium text-claude-dark">支持哪些支付方式?</h3>
|
|
207
|
+
<p class="mt-2 text-sm text-claude-dark/60">目前支持支付宝扫码支付。后续将支持微信支付等更多支付方式。</p>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</main>
|
|
213
|
+
|
|
214
|
+
<!-- Alipay QR Payment Modal -->
|
|
215
|
+
<div id="paymentModal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm">
|
|
216
|
+
<div class="bg-white rounded-2xl shadow-xl max-w-sm w-full mx-4 p-6">
|
|
217
|
+
<div class="text-center">
|
|
218
|
+
<h3 class="text-lg font-semibold text-claude-dark mb-1">支付宝扫码支付</h3>
|
|
219
|
+
<p class="text-sm text-claude-dark/60 mb-4">请使用支付宝扫描下方二维码完成支付</p>
|
|
220
|
+
|
|
221
|
+
<!-- QR Code Container -->
|
|
222
|
+
<div class="flex justify-center mb-4">
|
|
223
|
+
<div id="qrCodeContainer" class="w-64 h-64 bg-claude-cream/50 rounded-xl flex items-center justify-center border border-claude-dark/10">
|
|
224
|
+
<img id="qrCodeImg" src="" alt="支付宝二维码" class="hidden w-56 h-56 object-contain">
|
|
225
|
+
<div id="qrLoading" class="flex flex-col items-center space-y-2">
|
|
226
|
+
<svg class="w-8 h-8 text-claude-orange animate-spin" fill="none" viewBox="0 0 24 24">
|
|
227
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
228
|
+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
229
|
+
</svg>
|
|
230
|
+
<span class="text-sm text-claude-dark/50">生成二维码中...</span>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<!-- Payment Info -->
|
|
236
|
+
<div class="mb-4 p-3 bg-claude-cream/50 rounded-lg">
|
|
237
|
+
<p class="text-sm text-claude-dark/70">支付金额:<span id="paymentAmount" class="font-bold text-claude-orange text-lg"></span> 元</p>
|
|
238
|
+
<p class="text-xs text-claude-dark/40 mt-1">订单号:<span id="paymentOrderNo"></span></p>
|
|
239
|
+
</div>
|
|
240
|
+
|
|
241
|
+
<div id="paymentStatus" class="hidden mb-4 p-3 rounded-lg text-sm"></div>
|
|
242
|
+
|
|
243
|
+
<div class="flex space-x-3">
|
|
244
|
+
<button
|
|
245
|
+
onclick="closePaymentModal()"
|
|
246
|
+
class="flex-1 py-2.5 px-4 bg-claude-dark/5 text-claude-dark font-medium rounded-lg hover:bg-claude-dark/10 transition-colors text-sm"
|
|
247
|
+
>
|
|
248
|
+
取消支付
|
|
249
|
+
</button>
|
|
250
|
+
<button
|
|
251
|
+
onclick="checkPaymentStatus()"
|
|
252
|
+
id="checkPayBtn"
|
|
253
|
+
class="flex-1 py-2.5 px-4 bg-claude-orange text-white font-medium rounded-lg hover:bg-claude-orange/90 transition-colors text-sm"
|
|
254
|
+
>
|
|
255
|
+
我已支付
|
|
256
|
+
</button>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
<script>
|
|
263
|
+
var currentOrderNo = null;
|
|
264
|
+
var pollTimer = null;
|
|
265
|
+
|
|
266
|
+
async function handleSubscribe(plan) {
|
|
267
|
+
// Show modal and start loading
|
|
268
|
+
var modal = document.getElementById('paymentModal');
|
|
269
|
+
var qrImg = document.getElementById('qrCodeImg');
|
|
270
|
+
var qrLoading = document.getElementById('qrLoading');
|
|
271
|
+
var statusEl = document.getElementById('paymentStatus');
|
|
272
|
+
|
|
273
|
+
modal.classList.remove('hidden');
|
|
274
|
+
qrImg.classList.add('hidden');
|
|
275
|
+
qrLoading.classList.remove('hidden');
|
|
276
|
+
statusEl.classList.add('hidden');
|
|
277
|
+
|
|
278
|
+
try {
|
|
279
|
+
var res = await fetch('/api/payment/create-order', {
|
|
280
|
+
method: 'POST',
|
|
281
|
+
headers: { 'Content-Type': 'application/json' },
|
|
282
|
+
credentials: 'same-origin',
|
|
283
|
+
body: JSON.stringify({ plan: plan }),
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
var data = await res.json();
|
|
287
|
+
|
|
288
|
+
if (data.success) {
|
|
289
|
+
currentOrderNo = data.orderNo;
|
|
290
|
+
document.getElementById('paymentAmount').textContent = data.amount;
|
|
291
|
+
document.getElementById('paymentOrderNo').textContent = data.orderNo;
|
|
292
|
+
|
|
293
|
+
qrImg.src = data.qrCode;
|
|
294
|
+
qrImg.classList.remove('hidden');
|
|
295
|
+
qrLoading.classList.add('hidden');
|
|
296
|
+
|
|
297
|
+
// Start polling for payment status
|
|
298
|
+
startPaymentPolling();
|
|
299
|
+
} else {
|
|
300
|
+
qrLoading.innerHTML = '<span class="text-sm text-red-500">' + (data.error || '创建订单失败') + '</span>';
|
|
301
|
+
}
|
|
302
|
+
} catch (err) {
|
|
303
|
+
qrLoading.innerHTML = '<span class="text-sm text-red-500">网络错误,请重试</span>';
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function startPaymentPolling() {
|
|
308
|
+
if (pollTimer) clearInterval(pollTimer);
|
|
309
|
+
pollTimer = setInterval(async function() {
|
|
310
|
+
if (!currentOrderNo) return;
|
|
311
|
+
try {
|
|
312
|
+
var res = await fetch('/api/payment/check/' + currentOrderNo, { credentials: 'same-origin' });
|
|
313
|
+
var data = await res.json();
|
|
314
|
+
if (data.success && data.status === 'paid') {
|
|
315
|
+
clearInterval(pollTimer);
|
|
316
|
+
onPaymentSuccess();
|
|
317
|
+
}
|
|
318
|
+
} catch (e) {
|
|
319
|
+
// Silently retry
|
|
320
|
+
}
|
|
321
|
+
}, 3000);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function checkPaymentStatus() {
|
|
325
|
+
if (!currentOrderNo) return;
|
|
326
|
+
|
|
327
|
+
var btn = document.getElementById('checkPayBtn');
|
|
328
|
+
var statusEl = document.getElementById('paymentStatus');
|
|
329
|
+
btn.disabled = true;
|
|
330
|
+
btn.textContent = '查询中...';
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
var res = await fetch('/api/payment/check/' + currentOrderNo, { credentials: 'same-origin' });
|
|
334
|
+
var data = await res.json();
|
|
335
|
+
|
|
336
|
+
if (data.success && data.status === 'paid') {
|
|
337
|
+
onPaymentSuccess();
|
|
338
|
+
} else {
|
|
339
|
+
statusEl.className = 'mb-4 p-3 rounded-lg text-sm bg-yellow-50 border border-yellow-200 text-yellow-700';
|
|
340
|
+
statusEl.textContent = '暂未检测到支付,请确认支付完成后重试';
|
|
341
|
+
statusEl.classList.remove('hidden');
|
|
342
|
+
}
|
|
343
|
+
} catch (err) {
|
|
344
|
+
statusEl.className = 'mb-4 p-3 rounded-lg text-sm bg-red-50 border border-red-200 text-red-700';
|
|
345
|
+
statusEl.textContent = '查询失败,请稍后重试';
|
|
346
|
+
statusEl.classList.remove('hidden');
|
|
347
|
+
} finally {
|
|
348
|
+
btn.disabled = false;
|
|
349
|
+
btn.textContent = '我已支付';
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function onPaymentSuccess() {
|
|
354
|
+
var statusEl = document.getElementById('paymentStatus');
|
|
355
|
+
statusEl.className = 'mb-4 p-3 rounded-lg text-sm bg-green-50 border border-green-200 text-green-700';
|
|
356
|
+
statusEl.textContent = '支付成功!正在跳转到控制台...';
|
|
357
|
+
statusEl.classList.remove('hidden');
|
|
358
|
+
|
|
359
|
+
if (pollTimer) clearInterval(pollTimer);
|
|
360
|
+
|
|
361
|
+
setTimeout(function() {
|
|
362
|
+
window.location.href = '/dashboard';
|
|
363
|
+
}, 1500);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function closePaymentModal() {
|
|
367
|
+
document.getElementById('paymentModal').classList.add('hidden');
|
|
368
|
+
if (pollTimer) clearInterval(pollTimer);
|
|
369
|
+
currentOrderNo = null;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Close modal on backdrop click
|
|
373
|
+
document.getElementById('paymentModal').addEventListener('click', function(e) {
|
|
374
|
+
if (e.target === this) closePaymentModal();
|
|
375
|
+
});
|
|
376
|
+
</script>
|
|
377
|
+
|
|
378
|
+
</body>
|
|
379
|
+
</html>
|