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
2 changes: 1 addition & 1 deletion docs/user-stories.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
>
> **v1.16(2026-08-17)· B 交互(UE)优化(rant `2026-08-17T15:50:05`).** **toast 分级**(成功 success / 错误 error / 信息 info,39 个调用点全部分级着色);**按钮 loading 态**(充值 / 加额 / 部门确认 / 上架提交 → 转圈 + 禁用,模拟反馈后恢复);**API Key 复制反馈**(复制后按钮短暂变「已复制 ✓」,1.2s 恢复,降级路径「请 Ctrl+C」);**键盘可达**(充值金额 / 加额金额·原因 / 部门名称·配额 Enter 提交;topup/raise/dept 行内卡片 Esc 关闭;打开时自动聚焦)。**rant 15:50:05 全部验收项满足,UI 美化与 UE 优化波收官(PR #38/#39/#40,docs v1.14→v1.16)。**
> **v1.17(2026-08-17)· 多角度 UI/UE 深化(rant `2026-08-17T16:57:17`,分批 PR).** **A. 清除原生弹窗 ✓(PR #41)**:约 5 处原生确认/输入弹窗(key 删除、共享下架、部门删除、API Key 新建/改名、运营者/成员充值)全部改为**行内二次确认**(按钮变「确认删除?」红色态,3 秒无操作或 Esc 还原,再次点击执行)与**行内编辑**(行内展开输入框,Enter 确认 / Esc 取消);抽象可复用 `confirmInline` / `inlineForm` 组件全站统一;`grep ui/` 无原生弹窗残留。**B. 相对时间显示 ✓(PR #42)**:新增 `timeAgo` 格式化(`刚刚 / N 分钟前 / N 小时前 / 昨天 / MM-DD`,hover `title` 显示完整绝对时间),交易列表、加额申请列表、共享列表(新增「上架时间」列)与 API Key 最近使用时间统一使用。**C. 数字列对齐 ✓(PR #43)**:价格 / 点数 / 已用 / 额度 / 余额等**数字列统一右对齐 + 等宽字体**(`--mono` + `tabular-nums`,新增 `.table .num` 类,覆盖市场输入/输出价与上下文、交易 Token 用量/点数、共享已用/额度·单价·收益、成员配额/剩余、部门成员数·月分配·已用·剩余、运营者余额、加额申请点数),时间列 / 状态列保持左对齐;金额统一 `D.fmt`(整数千分位、小数 2 位)全覆盖检查无遗漏。其余 D–G(`:focus-visible` 与快捷键、行内校验错误、视图过渡、细节一致性)分批落地。**D. 键盘可达性 / 无障碍 ✓(PR #44)**:全局 `:focus-visible` 焦点环(accent 色 outline,Tab 导航清晰可见;输入类控件沿用边框高亮不叠加);**全局快捷键**:`/` 聚焦市场搜索框(输入框内不触发)、数字 **1-7** 切换侧边栏视图(仪表盘/市场/共享/钱包/交易/管理/设置,带 title 与右侧键位角标提示,Cmd/Ctrl+数字 不劫持)、Esc 关闭行内新建 Key;侧边栏导航按钮补 `title`(快捷键提示)。**E. 表单行内校验错误 ✓(PR #45)**:新增 `setFieldError(input, msg)` / `clearFieldError(input)`(输入框**红边框** + 字段下方**红字小号行内文案**,输入修正自动清除,打开表单时重置);覆盖**充值金额**(自定义金额非法)、**申请加额**(点数/原因)、**部门表单**(名称/配额/重名)、**共享上架表单**(API Key/厂商·Plan·模型·额度),提交失败不再仅依赖 toast,聚焦首个错误字段。**F. 视图切换过渡 ✓(PR #46)**:页面切换加轻量动画(`.view:not(.hidden)` **fade + 轻微上移 6px,150ms** `viewIn`,替代生硬切换);数据表格更新无闪烁(`.table tbody` **fade-in** `tbodyIn`,新增 `pulseTbody` 在静态 tbody 重渲染后重启动画,动态表格整表重建自动生效)。**G. 细节一致性 ✓(PR #47)**:一致性审计确认——**所有数字/金额统一 `D.fmt`(千分位/2 位小数)**(侧边栏余额、统计卡、表格、钱包点数格式一致)、已用/额度展示统一;表格操作按钮统一小号样式(`padding:4px 10px;font-size:12px`);**行内编辑校验统一走行内错误**(inlineForm 校验失败由 toast 改为 `setFieldError` 红边框+行内文案,API Key 改名/运营者充值/成员充值 3 处对齐 item E);子文本字号统一(11px→12px);上架 toast 单价措辞统一「点/1M(自动)」;移除 3 处「(未生效)」残留文案。**rant 16:57:17 全部验收项满足(A–G 七项,PR #41–#47),UI/UE 深化波收官。**
> **v1.18(2026-08-17)· UI/UE 第三轮多角度深化(rant `2026-08-17T18:06:09`,分批 PR).** **A. 仪表盘数据可视化 ✓(PR #48)**:纯 SVG sparkline(零外部依赖,手写 path,颜色用现有 CSS 变量):「本月点数变化」卡片按天聚合近 7 日净变化画迷你折线图(渐变填充,每点 `<title>` hover 显示当天数值);「我的共享」卡显示共享收益累计趋势 sparkline(`--ok` 色),无上架 key 时保留空状态不画图。其余 B–G(亮色主题、移动端卡片化、搜索增强、动效与系统偏好、动态标题、其他细节)分批落地。
> **v1.18(2026-08-17)· UI/UE 第三轮多角度深化(rant `2026-08-17T18:06:09`,分批 PR).** **A. 仪表盘数据可视化 ✓(PR #48)**:纯 SVG sparkline(零外部依赖,手写 path,颜色用现有 CSS 变量):「本月点数变化」卡片按天聚合近 7 日净变化画迷你折线图(渐变填充,每点 `<title>` hover 显示当天数值);「我的共享」卡显示共享收益累计趋势 sparkline(`--ok` 色),无上架 key 时保留空状态不画图。**B. 亮色主题 ✓(PR #49)**:CSS 变量重构——新增 `:root[data-theme="light"]` 全套变量重定义(--bg/--bg-card/--border/--text 等),并把原先硬编码颜色(表格行边框/斑马纹、卡片 hover 阴影、确认态、spinner、遮罩)抽为语义变量(--table-row-border/--table-stripe/--card-hover-border/--card-shadow/--danger-soft/--danger-text/--spin-track/--overlay)双主题共用;侧边栏加**日/月 SVG 切换按钮**(按当前主题显隐图标),**localStorage 记忆**(atp-theme),首次加载尊重 **`prefers-color-scheme`**;两主题对比度均达标(正文/次要文字/边框层次清晰)。其余 B–G(亮色主题、移动端卡片化、搜索增强、动效与系统偏好、动态标题、其他细节)分批落地。
> **v1.12(2026-08-17)· 移除「组织设置 Organization settings」表单.** 组织管理页只保留部门列表(部门 CRUD + 每月点数分配),删除底部「组织设置」表单(组织名称 / 默认成员配额 / 开关)。「关闭外部注册」属**部署配置项,不在 UI 中设置**(US-16 标注);「成员自助申请加额需管理员审批」开关移除后,申请加额流程**默认需审批**(US-20 说明)。
> **v1.11(2026-08-17)· 管理视图移除独立「Key 池」管理,统一走「上架 key」.** 管理员与普通用户一样通过**共享管理页「上架新 key」**(选厂商 → Plan → 模型、填 key、声明额度、可用时间段)配置上游 key——企业场景下管理员上架、员工消费,本质上就是 key 池;不再有独立的管理员 Key 池界面。移除 Admin「Key 池」tab(成员管理 / 用量报表 / 组织管理 / 平台运营保留)。「Key 池」保留为**数据层概念**(平台持有的上游 key 集合,见 docs/architecture.md 4.2)。更新 US-12 / 企业流程 / 对齐表。
> **v1.10(2026-08-17)· 上架表单"可用时间段"结构化.** 上架 key 的可用时间段改为**正式字段**(星期多选 + 起止时间,可多选;留空 = 全天不限),后端可解析生效;**备注只作纯文本**,不承载任何逻辑。共享列表展示可用时间段(如「周一~周五 09:00-18:00」),未设置显示「全天」。更新 US-8 / US-9 AC。
Expand Down
5 changes: 5 additions & 0 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ ui/
- **使用**:`lastDayLabels(n)` 生成近 n 天 MM-DD 标签;`dailySeries(days, filter)` 按天聚合交易点数;仪表盘「本月点数变化」画近 7 日净变化折线(渐变填充),「我的共享」画收益累计趋势(`--ok` 色,无数据保留空状态);
- 样式 `.sparkline`(宽 100% / 高 38px)。

## 主题约定(v1.18,rant 2026-08-17T18:06:09 B 亮色主题)

- **双主题**:`:root`(深色默认)与 `:root[data-theme="light"]` 重定义全套颜色变量;**禁止硬编码颜色**——表格行边框/斑马纹、卡片 hover 阴影、确认态、spinner、遮罩均用语义变量(`--table-row-border` / `--table-stripe` / `--card-hover-border` / `--card-shadow` / `--danger-soft` / `--danger-text` / `--spin-track` / `--overlay`);
- **切换**:侧边栏 `#theme-toggle`(日/月 SVG 图标按主题显隐)→ 设 `document.documentElement.dataset.theme`,`localStorage["atp-theme"]` 记忆;首次加载无记忆时尊重 `prefers-color-scheme`。

## 数据说明

- 点数规则与机制细节见 `docs/user-stories.md`(v1.8:机制说明不再进入面向用户的界面文案);UI 只呈现结果(余额数字、模型价格点数、交易金额/类型/状态、可用/繁忙)
Expand Down
69 changes: 62 additions & 7 deletions ui/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
--ok: #3ecf8e;
--warn: #e5b45b;
--danger: #e5666a;
--danger-soft: rgba(229, 102, 106, 0.15);
--danger-text: #ff9d9f;
--card-hover-border: #3a4a63;
--card-shadow: 0 12px 30px rgba(0,0,0,.38);
--table-row-border: rgba(42,51,66,.5);
--table-stripe: rgba(255,255,255,.018);
--spin-track: rgba(255,255,255,.35);
--overlay: rgba(14,17,22,.72);
--radius: 12px;
--radius-sm: 8px;
--sidebar-w: 240px;
Expand All @@ -26,6 +34,33 @@
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* 亮色主题(rant 18:06:09 B:CSS 变量重构,侧边栏切换 + localStorage 记忆 + prefers-color-scheme) */
:root[data-theme="light"] {
--bg: #f4f6fa;
--bg-soft: #e9edf3;
--bg-card: #ffffff;
--bg-hover: #e2e8f0;
--border: #d5dde8;
--text: #1c2330;
--text-dim: #55627a;
--text-mute: #8a94a6;
--accent: #159a92;
--accent-soft: rgba(21, 154, 146, 0.12);
--accent-text: #0f7f78;
--ok: #128a5d;
--warn: #b07d1e;
--danger: #cf4550;
--danger-soft: rgba(207, 69, 80, 0.12);
--danger-text: #cf4550;
--card-hover-border: #c4cdda;
--card-shadow: 0 12px 30px rgba(40,55,80,.14);
--table-row-border: rgba(150,165,185,.4);
--table-stripe: rgba(25,40,60,.025);
--spin-track: rgba(0,0,0,.25);
--overlay: rgba(20,26,36,.5);
--shadow: 0 8px 24px rgba(40,55,80,.12);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }
Expand Down Expand Up @@ -87,9 +122,9 @@ body {

/* 行内二次确认(rant 16:57:17 A:按钮变「确认删除?」红色态,3 秒无操作还原) */
.btn.confirming {
background: rgba(229, 102, 106, 0.15);
background: var(--danger-soft);
border-color: var(--danger);
color: #ff9d9f;
color: var(--danger-text);
font-weight: 700;
}
/* 行内编辑容器(输入框 + 确认/取消,Enter 确认 / Esc 取消) */
Expand Down Expand Up @@ -169,7 +204,7 @@ select.input option { background: var(--bg-card); }
.card h3 { font-size: 15px; margin-bottom: 14px; color: var(--text); }

/* 卡片 hover 微交互(rant 15:50:05 A.3:阴影/边框轻提升) */
.card:hover { border-color: #3a4a63; box-shadow: 0 12px 30px rgba(0,0,0,.38); }
.card:hover { border-color: var(--card-hover-border); box-shadow: var(--card-shadow); }

.card-grid {
display: grid;
Expand Down Expand Up @@ -217,13 +252,13 @@ select.input option { background: var(--bg-card); }
border-bottom: 1px solid var(--border);
white-space: nowrap;
}
.table td { padding: 10px 12px; border-bottom: 1px solid rgba(42,51,66,.5); white-space: nowrap; }
.table td { padding: 10px 12px; border-bottom: 1px solid var(--table-row-border); white-space: nowrap; }
/* 数字列(rant 16:57:17 C:价格/点数/已用/额度/余额 右对齐 + 等宽字体,便于扫读) */
.table .num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.table th.num { text-align: right; }
.table th.num .th-sort { text-align: right; }
/* 斑马纹(rant 15:50:05 A.3:行 hover 高亮保留,hover 覆盖斑马纹) */
.table tbody tr:nth-child(even) { background: rgba(255,255,255,.018); }
.table tbody tr:nth-child(even) { background: var(--table-stripe); }
.table tbody tr:hover { background: var(--bg-hover); }

.badge {
Expand Down Expand Up @@ -431,6 +466,26 @@ select.input option { background: var(--bg-card); }
padding: 14px 12px;
}
.sidebar-top { display: flex; align-items: center; gap: 10px; padding: 2px 6px 14px; border-bottom: 1px solid var(--border); }
.brand-text { flex: 1; min-width: 0; }
.brand-text strong { font-size: 15px; display: block; }
.brand-text span { color: var(--text-mute); font-size: 11px; }
/* 主题切换按钮(rant 18:06:09 B:日/月 SVG 图标,按当前主题显隐) */
.theme-toggle {
flex-shrink: 0;
width: 30px; height: 30px;
display: inline-flex; align-items: center; justify-content: center;
border: 1px solid var(--border);
background: var(--bg-soft);
color: var(--text-dim);
border-radius: var(--radius-sm);
cursor: pointer;
transition: all .15s;
}
.theme-toggle:hover { color: var(--accent-text); border-color: var(--accent); }
.theme-toggle svg { width: 15px; height: 15px; }
.theme-toggle .ico-moon { display: none; }
:root[data-theme="light"] .theme-toggle .ico-sun { display: none; }
:root[data-theme="light"] .theme-toggle .ico-moon { display: block; }
.brand-text { display: flex; flex-direction: column; line-height: 1.3; }
.brand-text strong { font-size: 14px; }
.brand-text span { color: var(--text-mute); font-size: 11px; }
Expand Down Expand Up @@ -503,7 +558,7 @@ select.input option { background: var(--bg-card); }

.modal-overlay {
position: fixed; inset: 0;
background: rgba(14, 17, 22, .72);
background: var(--overlay);
display: flex; align-items: center; justify-content: center;
z-index: 1000; padding: 24px;
}
Expand Down Expand Up @@ -562,7 +617,7 @@ select.input option { background: var(--bg-card); }
.spin {
display: inline-block;
width: 12px; height: 12px;
border: 2px solid rgba(255,255,255,.35);
border: 2px solid var(--spin-track);
border-top-color: currentColor;
border-radius: 50%;
vertical-align: -2px;
Expand Down
4 changes: 4 additions & 0 deletions ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ <h1>AITokenPool</h1>
<strong>AITokenPool</strong>
<span id="mode-label">共享市场 · 角色视图</span>
</div>
<button type="button" class="theme-toggle" id="theme-toggle" title="切换亮色 / 深色主题">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="ico-sun" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="ico-moon" aria-hidden="true"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
</button>
</div>

<nav class="nav" id="nav"></nav>
Expand Down
13 changes: 13 additions & 0 deletions ui/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,19 @@
renderView("dashboard");
$("#side-balance").textContent = D.fmt(D.USER.balance);

// 主题(rant 18:06:09 B):localStorage 记忆,首次加载尊重 prefers-color-scheme
const savedTheme = (() => { try { return localStorage.getItem("atp-theme"); } catch (e) { return null; } })();
const initialTheme = savedTheme === "light" || savedTheme === "dark"
? savedTheme
: (window.matchMedia && window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark");
document.documentElement.dataset.theme = initialTheme;
$("#theme-toggle").addEventListener("click", () => {
const next = document.documentElement.dataset.theme === "light" ? "dark" : "light";
document.documentElement.dataset.theme = next;
try { localStorage.setItem("atp-theme", next); } catch (e) { /* 隐私模式忽略 */ }
toast("已切换为" + (next === "light" ? "亮色" : "深色") + "主题", "info");
});

// 全局快捷键(rant 16:57:17 D):/ 聚焦市场搜索;数字 1-7 切换侧边栏视图;Esc 关闭行内新建 key
document.addEventListener("keydown", (e) => {
const t = e.target;
Expand Down
Loading