Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ python3 -m http.server 8000 --directory ui

## 页面清单

登录页:单一入口(邮箱登录占位),不做公共版/企业版二选一;登录页含 **点数机制说明(US-2)**(1 点 ≈ 1 元 · 消费可小数 · 每日赠送 1 点等),并提供「**游客浏览**」入口(US-1)。
登录页:单一入口(邮箱登录占位),不做公共版/企业版二选一;提供「**游客浏览**」入口(US-1)。

**游客模式(US-1)**:未登录可点击「先逛逛市场」免登录进入模型市场——
- 游客可:浏览模型、搜索、厂商筛选、排序、查看点数价格;
Expand All @@ -37,10 +37,10 @@ python3 -m http.server 8000 --directory ui

同一套界面(角色视图):

1. 仪表盘 Dashboard — 点数余额、本月用量、共享收益、最近交易、点数来源(分组展示有效期:赠送当日有效 / 收益与充值永久)
1. 仪表盘 Dashboard — 点数余额、本月用量、共享收益、点数来源(点数构成分组)
2. 模型市场 Marketplace — 模型浏览、搜索、厂商筛选、排序(按价格/上下文);可用性标注「多 key · 自动故障转移」(该模型配置多个上游 key,架构 v0.2 路由策略);每行「使用 / 消费」入口 → 聊天 Mock 模拟调用(按模型输出参考价扣小数点数,如 -0.38 点,产生消费交易;余额不足时阻断并提示)
3. 共享管理 Sharing — 默认只显示统计 + 我的共享列表(key 脱敏展示,可暂停/恢复/重新上架/彻底删除);点击"+ 添加 / 上架新 key"展开上架表单(须填 API Key,平台加密托管;分享者只填声明额度,单价由平台按模型定价自动计算并展示参考价),提交成功或取消后自动收起
4. 钱包 Wallet — 点数余额、点数来源(每日赠送 1 点 · 有效期至今日 · 连续第 N 天 / 共 10 天;收益永久;充值永久)、**充值入口(US-4:模拟流程——输入点数 → 余额增加 → topup 交易记录,永久有效点数;文案注明"演示,真实支付后续接入";提现仍 disabled)**、**申请加额(US-20:企业成员余额低时申请更多点数 → 提交后等待管理员审批,与组织设置开关联动)**;收支明细已去重,统一到【交易记录】(页内提供跳转提示)
4. 钱包 Wallet — 点数余额、点数来源(点数构成分组)、**充值入口(US-4:模拟流程——输入点数 → 余额增加 → topup 交易记录;文案注明"演示,真实支付后续接入";提现仍 disabled)**、**申请加额(US-20:企业成员余额低时申请更多点数 → 提交后等待管理员审批,与组织设置开关联动)**;收支明细已去重,统一到【交易记录】(页内提供跳转提示)
5. 交易记录 Transactions — 消费/收益/充值/提现/赠送(gift)唯一明细入口,Tab 筛选 + MRT 风格表格(列排序/列筛选/分页,与 Tab 叠加生效)
6. 设置 Settings — 账户、API Key 管理(完整增删改查:生成带名字、改名、删除需确认「删除后该 key 立即失效」、按名字搜索、一键复制完整 key——列表脱敏展示 atk_live_****xxxx,复制为完整值;file:// 下 clipboard API 受限时降级为选中+Ctrl/Cmd+C)、通知、偏好
7. 管理视图 Admin(管理员 / 运营者角色专属)— Key 池管理(添加/撤销)、成员管理(改部门:下拉可选部门或"未分配";任意金额充值,正整数校验;新注册成员默认未分配部门;**加额申请审批(US-20:待审批列表 → 批准=成员余额+申请点数 / 驳回)**)、用量报表(按模型/成员)、组织管理(部门列表 + 部门增删改查 + 每月点数分配,含部门汇总统计,未分配成员不计入任何部门;保留组织设置卡片,含"关闭外部注册"企业部署开关与"成员自助申请加额需管理员审批"开关——关掉后成员申请直接生效)、平台运营(运营者 = 宿主本人,职责最小化:① 运行概览——运行状态 / 用户数 / 共享 key 数 / 交易量 / 点数流入流出;② 用户充值——按用户名 / 邮箱搜索定位,输入点数金额(可为小数)确认后余额增加永久有效点数并产生一条交易记录)
Expand All @@ -58,8 +58,8 @@ ui/

## 数据说明

- 点数规则:**1 点 ≈ 1 元人民币(CNY)**;CNY 模型直接 1 元 = 1 点,USD 模型按 ~7.2 汇率折算为人民币点数;消费点数可为小数(金额保留 2 位小数)
- 点数机制(v1.7):每日赠送 1 点(当日有效,需当天登录领取,未登录日不发不积累;注册起连续 10 个自然日),钱包显示"今日赠送 +1 · 有效期至今日 · 连续第 N 天 / 共 10 天",先扣有有效期的赠送点数;分享收益与未来充值点数永久有效;**分享收益扣 10% 平台分成(收益 = 消费点数 × 90%)**;充值(US-4)为演示模拟流程(真实支付通道后续接入),提现暂不支持
- 点数规则与机制细节见 `docs/user-stories.md`(v1.8:机制说明不再进入面向用户的界面文案);UI 只呈现结果(余额数字、模型价格点数、交易金额/类型/状态、可用/繁忙)
- 消费模拟(聊天 Mock)按 输出参考价 × 0.19M tokens 计费,扣减小数点数并产生 consume 交易(US-6)
- 上架单价不由分享者手填:单价是模型×厂商的客观属性,平台按模型价格表自动计算(参考单价 = 该模型输出价 点数/1M);模型无定价数据时给出"按默认价"兜底,不报错
- 市场模型带 `multi` 标记:表示该模型配置多个上游 key → 标注「多 key · 自动故障转移」(见 `docs/architecture.md` v0.2 路由策略);消费模拟(聊天 Mock)按 输出参考价 × 0.19M tokens 计费,扣减小数点数并产生 consume 交易(US-6)
- 上架需提交 API Key(password 输入):平台加密托管、仅用于代理调用;共享列表只展示脱敏值(如 sk-****1234,前 3 后 4),不展示明文
Expand Down
11 changes: 0 additions & 11 deletions ui/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -310,17 +310,6 @@ select.input option { background: var(--bg-card); }
.login-foot a { color: var(--accent-text); text-decoration: none; }
.login-tip { margin-top: 14px; text-align: center; color: var(--text-mute); font-size: 11px; }

/* 登录页点数机制说明(US-2) */
.login-points {
margin-top: 18px; padding: 12px 14px;
background: rgba(78, 205, 196, 0.06);
border: 1px dashed var(--border);
border-radius: 10px;
}
.login-points h4 { font-size: 13px; margin-bottom: 8px; color: var(--text); }
.login-points ul { margin: 0; padding-left: 16px; display: flex; flex-direction: column; gap: 5px; }
.login-points li { font-size: 12px; color: var(--text-dim); line-height: 1.5; }

/* ---------- 应用布局 ---------- */

.app { display: flex; height: 100vh; overflow: hidden; }
Expand Down
21 changes: 4 additions & 17 deletions ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,6 @@ <h1>AITokenPool</h1>
<button type="button" class="btn btn-ghost btn-block" id="guest-browse-btn">先逛逛市场 <span class="en">(Guest browse)</span></button>
<p class="login-foot">还没有账号?<a href="#">注册 <span class="en">Register</span></a> · <a href="#">找回密码</a></p>
<p class="login-tip">静态演示原型 · 数据为内嵌 mock,无真实后端 · 管理员与普通用户由账号角色决定登录后看到的界面</p>

<!-- 点数机制说明(US-2):登录页可见 -->
<div class="login-points">
<h4>点数机制 <span class="en">Points</span></h4>
<ul>
<li>1 点 ≈ 1 元人民币 · 消费点数可为小数(如 -0.37 点)</li>
<li>每日赠送 1 点(当日有效)· 连续 10 天</li>
<li>分享收益 &amp; 充值点数永久有效 · 分享收益扣 10% 平台分成</li>
<li>未登录可先浏览市场;使用 / 消费需登录</li>
</ul>
</div>
</div>
</div>

Expand Down Expand Up @@ -170,7 +159,7 @@ <h3>上架新 key <span class="en">List a key</span></h3>
</div>
<div class="card">
<h3>我的共享列表 <span class="en">My listings</span></h3>
<p class="muted">收益为已扣 10% 平台分成后的金额(平台抽取 10% 作为运营费用)</p>
<p class="muted">收益已到账</p>
<div class="table-wrap compact">
<table class="table">
<thead><tr><th>模型</th><th>Key</th><th>已用/额度</th><th>单价</th><th>收益</th><th>状态</th><th></th></tr></thead>
Expand All @@ -191,7 +180,6 @@ <h2>钱包 <span class="en">Wallet</span></h2>
<div>
<h3>点数余额 <span class="en">Points balance</span></h3>
<div class="balance-big" id="wallet-balance">0</div>
<p>1 点 ≈ 1 元 <span class="en">(1 point ≈ 1 CNY)</span> · 消费点数可为小数</p>
</div>
<div class="wallet-actions">
<button class="btn btn-primary" id="topup-btn">充值 <span class="en">Top up</span></button>
Expand All @@ -202,21 +190,20 @@ <h3>点数余额 <span class="en">Points balance</span></h3>
</div>
<div class="card">
<h3>点数来源 <span class="en">Point sources</span></h3>
<p class="muted">每日赠送 1 点 · 当日有效(先扣有有效期的赠送点数);收益 / 充值点数永久有效</p>
<div class="mini-list" id="points-sources"></div>
</div>
<div class="card">
<p class="wallet-hint">收支明细已统一到
<button class="btn btn-ghost" id="wallet-goto-tx">交易记录</button>
——涵盖消费(用别人的 key)、收益(别人用我的 key,已扣 10% 平台分成)、充值、提现、赠送(每日 1 点 · 连续 10 天)</p>
——涵盖消费、收益、充值、提现、赠送</p>
</div>
</section>

<!-- 交易记录 Transactions -->
<section class="view hidden" id="view-transactions">
<header class="page-head">
<h2>交易记录 <span class="en">Transactions</span></h2>
<p>涵盖消费(用别人的 key)、收益(别人用我的 key,已扣 10% 平台分成)、充值、提现、赠送(每日 1 点 · 连续 10 天)</p>
<p>涵盖消费、收益、充值、提现、赠送</p>
</header>
<div class="tabs" id="tx-tabs">
<button class="tab active" data-tx-tab="all">全部</button>
Expand Down Expand Up @@ -408,7 +395,7 @@ <h3 id="chat-title">使用模型</h3>
<h3>充值点数 <span class="en">Top up</span></h3>
<button type="button" class="btn btn-ghost" data-modal-close="topup-modal">✕</button>
</div>
<p class="muted">演示流程:真实支付通道后续接入。充值获得<strong>永久有效点数</strong>(1 点 ≈ 1 元)。</p>
<p class="muted">演示流程:真实支付通道后续接入。</p>
<div class="form">
<label>选择金额(点数)
<div class="topup-presets">
Expand Down
15 changes: 6 additions & 9 deletions ui/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@
const recent = txs.slice(0, 5);

$("#dash-stats").innerHTML = [
stat("点数余额 Points", D.fmt(D.USER.balance), "1 点 ≈ 1 元", "accent"),
stat("点数余额 Points", D.fmt(D.USER.balance), "", "accent"),
stat("本月用量 Usage", D.fmt(monthUse) + " 点", "共 " + txs.filter((t) => t.type === "consume").length + " 笔消费"),
stat("共享收益 Earnings", "+" + D.fmt(monthEarn) + " 点", "已扣 10% 平台分成 · " + D.SHARINGS.filter((s) => s.status === "on").length + " 个 key 上架中"),
stat("共享收益 Earnings", "+" + D.fmt(monthEarn) + " 点", D.SHARINGS.filter((s) => s.status === "on").length + " 个 key 上架中"),
stat("交易笔数 Trades", txs.length + " 笔", "含充值 / 提现 / 消费 / 收益 / 赠送"),
].join("");

Expand Down Expand Up @@ -273,13 +273,10 @@
if (activeView === "dashboard") renderDashboard();
}

/* --- 点数来源(G2:钱包 / 仪表盘统一展示来源与有效期,赠送当日有效 / 收益充值永久) --- */
/* --- 点数来源(G2:钱包 / 仪表盘统一展示点数构成) --- */

function pointSourceItem(s) {
const cls = s.validity === "永久有效" ? "ok" : "warn";
return '<div class="mini-item"><div><div class="t">' + esc(s.label) +
' <span class="badge ' + cls + '">' + esc(s.validity) + "</span></div>" +
'<div class="d">' + esc(s.note) + "</div></div>" +
return '<div class="mini-item"><div><div class="t">' + esc(s.label) + "</div></div>" +
'<div class="r"><span class="pts">' + (s.pts > 0 ? "+" : "") + D.fmt(s.pts) + "</span></div></div>";
}

Expand All @@ -297,7 +294,7 @@
// 钱包只做余额与资金操作;收支明细统一到【交易记录】(见 index.html wallet-hint)
$("#side-balance").textContent = D.fmt(D.USER.balance);
$("#wallet-balance").textContent = D.fmt(D.USER.balance);
// 点数来源 / 有效期(G2:赠送当日有效剩 N 天 · 收益/充值永久;消费先扣赠送)
// 点数来源构成(v1.8:只展示构成,机制细节进 docs)
renderPointSources();
}

Expand Down Expand Up @@ -329,7 +326,7 @@
if (top) top.pts = Math.round((top.pts + amt) * 100) / 100;
D.TRANSACTIONS.unshift({
id: Date.now(), time: nowTime(), type: "topup", partner: "—",
detail: "充值 · 模拟支付(永久有效 · 演示,真实支付后续接入)", tokens: "—", pts: +amt, status: "成功",
detail: "充值 · 模拟支付(演示,真实支付后续接入)", tokens: "—", pts: +amt, status: "成功",
});
$("#side-balance").textContent = D.fmt(D.USER.balance);
renderWallet();
Expand Down
25 changes: 12 additions & 13 deletions ui/js/data.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* ============================================================
AITokenPool UI Prototype — 内嵌 mock 数据
点数规则:1 点 ≈ 1 元人民币(CNY);USD 模型按 ~7.2 汇率折算(示例)
点数规则与机制细节见 docs/user-stories.md(v1.8:机制不进 UI)
============================================================ */

(function () {
Expand Down Expand Up @@ -45,12 +45,11 @@
// 当前用户(公共版)
USER: { name: "阿零", email: "demo@aitokenpool.local", balance: 12471 },

// 点数来源(v1.4 点数机制:每日赠送 1 点 / 当日有效 / 连续 10 天;分享收益与充值点数永久有效)
// G2:钱包 / 仪表盘按来源分组展示有效期——赠送「当日有效 · 剩 N 天」、收益 / 充值「永久有效」;消费先扣赠送
// 点数来源(v1.8:面向用户只展示构成,机制细节进 docs)
POINT_SOURCES: [
{ kind: "gift", label: "赠送点数", pts: 1, validity: "当日有效", note: "今日赠送 +1 · 有效期至今日 · 连续第 7 天 / 共 10 天(剩 3 天)" },
{ kind: "earn", label: "收益点数", pts: 12470, validity: "永久有效", note: "分享 key 赚取 · 永久有效" },
{ kind: "topup", label: "充值点数", pts: 0, validity: "永久有效", note: "永久有效 · 演示充值可用(US-4)" },
{ kind: "gift", label: "赠送点数", pts: 1 },
{ kind: "earn", label: "收益点数", pts: 12470 },
{ kind: "topup", label: "充值点数", pts: 0 },
],

// 加额申请(US-20:企业成员申请 → 管理员批准 / 驳回;mock 内嵌数据)
Expand All @@ -60,22 +59,22 @@

// 交易记录(消费 / 收益 / 充值 / 提现 / 赠送)——唯一明细数据源,钱包页与交易记录页共用此表
TRANSACTIONS: [
{ id: 13, time: "08-14 09:00", type: "gift", partner: "—", detail: "赠送 · 每日赠送 第 7 天 / 共 10 天(有效期至今日)", tokens: "—", pts: +1, status: "入账" },
{ id: 13, time: "08-14 09:00", type: "gift", partner: "—", detail: "赠送 · 每日赠送 +1", tokens: "—", pts: +1, status: "入账" },
{ id: 1, time: "08-13 20:15", type: "consume", partner: "deepseek-v4-flash", detail: "消费 · 用 shared key", tokens: "0.19M", pts: -0.37, status: "成功" },
{ id: 2, time: "08-13 19:02", type: "earn", partner: "glm-5.2", detail: "收益 · 我的 key 被消费(已扣 10% 平台分成)", tokens: "860K", pts: +378, status: "入账" },
{ id: 2, time: "08-13 19:02", type: "earn", partner: "glm-5.2", detail: "收益 · 我的 key 被消费", tokens: "860K", pts: +378, status: "入账" },
{ id: 3, time: "08-13 17:44", type: "consume", partner: "gpt-5.5-pro", detail: "消费 · 用 shared key", tokens: "45K", pts: -860, status: "成功" },
{ id: 4, time: "08-13 15:10", type: "earn", partner: "kimi-k3", detail: "收益 · 我的 key 被消费(已扣 10% 平台分成)", tokens: "1.5M", pts: +882, status: "入账" },
{ id: 4, time: "08-13 15:10", type: "earn", partner: "kimi-k3", detail: "收益 · 我的 key 被消费", tokens: "1.5M", pts: +882, status: "入账" },
{ id: 5, time: "08-13 11:36", type: "topup", partner: "—", detail: "充值", tokens: "—", pts: +5000, status: "成功" },
{ id: 6, time: "08-12 21:08", type: "consume", partner: "gemini-3.1-pro", detail: "消费 · 用 shared key", tokens: "2.1M", pts: -310, status: "成功" },
{ id: 7, time: "08-12 14:22", type: "earn", partner: "deepseek-v4-flash", detail: "收益 · 我的 key 被消费(已扣 10% 平台分成)", tokens: "3.0M", pts: +189, status: "入账" },
{ id: 7, time: "08-12 14:22", type: "earn", partner: "deepseek-v4-flash", detail: "收益 · 我的 key 被消费", tokens: "3.0M", pts: +189, status: "入账" },
{ id: 8, time: "08-12 09:41", type: "consume", partner: "claude-opus-4.7", detail: "消费 · 用 shared key", tokens: "22K", pts: -640, status: "成功" },
{ id: 9, time: "08-11 18:30", type: "withdraw", partner: "—", detail: "提现(占位)", tokens: "—", pts: -2000, status: "处理中" },
{ id: 10, time: "08-11 10:12", type: "earn", partner: "glm-5.2", detail: "收益 · 我的 key 被消费(已扣 10% 平台分成)", tokens: "700K", pts: +351, status: "入账" },
{ id: 10, time: "08-11 10:12", type: "earn", partner: "glm-5.2", detail: "收益 · 我的 key 被消费", tokens: "700K", pts: +351, status: "入账" },
{ id: 11, time: "08-10 16:05", type: "consume", partner: "doubao-seed-2.1-pro", detail: "消费 · 用 shared key", tokens: "540K", pts: -260, status: "成功" },
{ id: 12, time: "08-10 08:50", type: "earn", partner: "minimax-m3", detail: "收益 · 我的 key 被消费(已扣 10% 平台分成)", tokens: "2.4M", pts: +162, status: "入账" },
{ id: 12, time: "08-10 08:50", type: "earn", partner: "minimax-m3", detail: "收益 · 我的 key 被消费", tokens: "2.4M", pts: +162, status: "入账" },
],

// 我的共享(price = 按模型定价自动计算的输出单价 点数/1M;earned 为已扣 10% 平台分成后的累计收益;key 仅脱敏展示)
// 我的共享(price = 按模型定价自动计算的输出单价 点数/1M;earned = 累计收益;key 仅脱敏展示)
SHARINGS: [
{ id: 1, model: "glm-5.2", quota: 100000, used: 32800, price: 28, earned: 1611, status: "on", key: "sk-zhipu-9f2c41ab7d22" },
{ id: 2, model: "deepseek-v4-flash", quota: 80000, used: 51200, price: 2, earned: 1116, status: "on", key: "sk-ds-3b88d077aa91" },
Expand Down
Loading