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
1 change: 1 addition & 0 deletions ui/css/style.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -505,6 +505,7 @@ mark {
}
.pager button.active { border-color: var(--accent); color: var(--accent-text); }
.pager span { color: var(--text-mute); font-size: 12px; }
.pager .pager-ellipsis { min-width: 22px; text-align: center; user-select: none; }

/* MRT 风格表格:表头排序 + 列筛选 + 每页行数 */
.th-sort {
Expand Down
10 changes: 5 additions & 5 deletions ui/index.html
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AITokenPool</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%234ecdc4'/%3E%3Cstop offset='1' stop-color='%232a9d8f'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' rx='14' fill='url(%23g)'/%3E%3Ctext x='32' y='43' font-family='-apple-system,Segoe UI,Arial,sans-serif' font-size='30' font-weight='800' text-anchor='middle' fill='%23062021'%3EAT%3C/text%3E%3C/svg%3E">
<link rel="stylesheet" href="css/style.css?v=20260824-2">
<link rel="stylesheet" href="css/style.css?v=20260824-3">
</head>
<body>

Expand DownExpand Up@@ -683,9 +683,9 @@ <h3 id="chat-title">使用模型</h3>
</div>
</div>

<script src="js/api.js?v=20260824-2"></script>
<script src="js/data.js?v=20260824-2"></script>
<script src="js/i18n.js?v=20260824-2"></script>
<script src="js/app.js?v=20260824-2"></script>
<script src="js/api.js?v=20260824-3"></script>
<script src="js/data.js?v=20260824-3"></script>
<script src="js/i18n.js?v=20260824-3"></script>
<script src="js/app.js?v=20260824-3"></script>
</body>
</html>
49 changes: 41 additions & 8 deletions ui/js/app.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1385,6 +1385,11 @@
$("#tx-table").innerHTML = loadErrorHtml(T("tx.loadFail"), null, T("err.loadFail"));
return;
}
// 真后端分页(rant 2026-08-24T10:51:57):本地页码/每页行数与已加载页不一致 → 重新向后端拉取对应页
if (Live.transactions && (txTable.loadedPage !== txTable.page || txTable.loadedPageSize !== txTable.pageSize)) {
loadTransactions();
return;
}
let list = Live.transactions ? txsToView(Live.transactions.items || []) : [];
// 交易汇总条:与 tab + 列筛选联动,与表格可见行一致(rant 20:39:30 B)
renderTxSummary(filterRows(list, TX_COLUMNS, txTable.filters));
Expand All@@ -1396,6 +1401,8 @@
rows: list,
state: txTable,
onState: renderTransactions,
// 真后端分页(rant 2026-08-24T10:51:57):总数显示后端 total;页码点击 → onState → renderTransactions 页码不一致自动重拉
serverPaging: Live.transactions ? { total: Live.transactions.total || 0 } : null,
});
}

Expand All@@ -1417,14 +1424,19 @@
return p.join("&");
}

// P2-B:按 tab 拉取交易(后端分页;带时间段过滤)
// P2-B:按 tab 拉取交易(真后端分页 rant 2026-08-24T10:51:57:页码/每页行数随请求发出;
// loadedPage/loadedPageSize 记录已加载页,renderTransactions 发现页码不一致时自动重拉)
async function loadTransactions() {
if (!loggedIn()) return;
const type = txTab === "all" ? "" : txTab;
const range = txRangeParams();
const q = "/api/transactions?type=" + type + "&page=1&page_size=100" + (range ? "&" + range : "");
const page = Math.max(1, txTable.page || 1);
const pageSize = Math.min(100, Math.max(1, txTable.pageSize || 10));
const q = "/api/transactions?type=" + type + "&page=" + page + "&page_size=" + pageSize + (range ? "&" + range : "");
try {
await liveLoad("transactions", q);
txTable.loadedPage = page;
txTable.loadedPageSize = pageSize;
} catch (e) { Live.transactions = null; /* 登录态降级空态 */ }
// 趋势图数据(rant 2026-08-23T16:01:07 需求 2):独立拉取,失败不阻塞列表
const bucket = txTrendBucket();
Expand All@@ -1433,6 +1445,11 @@
if (Live.transactions) Live.transactions.trend = trend;
} catch (e) { if (Live.transactions) Live.transactions.trend = null; }
renderTransactions();
// 翻页后滚动到列表顶部(rant 2026-08-24T10:51:57 需求 4)
if (page > 1) {
const tbl = $("#tx-table");
if (tbl && tbl.scrollIntoView) tbl.scrollIntoView({ block: "start" });
}
}

// 交易记录导出 CSV(rant 20:46:57 E:Blob + a[download],UTF-8 BOM,文件名 aitokenpool-transactions-YYYYMMDD.csv;导出当前筛选可见行)
Expand DownExpand Up@@ -1540,8 +1557,20 @@
});
}

// 紧凑分页码(页数 > 9 时省略号收拢:1 … p-1 p p+1 … N;页数少则全量渲染)
function pagerButtons(page, pages) {
const out = [];
if (pages <= 9) { for (let i = 1; i <= pages; i++) out.push(i); return out; }
out.push(1);
if (page > 4) out.push("…");
for (let i = Math.max(2, page - 1); i <= Math.min(pages - 1, page + 1); i++) out.push(i);
if (page < pages - 3) out.push("…");
out.push(pages);
return out;
}

function buildDataTable(cfg) {
const { container, columns, rows, state, onState } = cfg;
const { container, columns, rows, state, onState, serverPaging } = cfg;

// 1) 筛选
let data = filterRows(rows, columns, state.filters);
Expand All@@ -1561,10 +1590,11 @@
});
}

// 3) 分页
const pages = Math.max(1, Math.ceil(data.length / state.pageSize));
// 3) 分页(serverPaging:总数取后端 total,行即当前页——服务端已翻页,不做本地 slice)
const totalRows = serverPaging ? serverPaging.total : data.length;
const pages = Math.max(1, Math.ceil(totalRows / state.pageSize));
if (state.page > pages) state.page = pages;
const pageRows = data.slice((state.page - 1) * state.pageSize, state.page * state.pageSize);
const pageRows = serverPaging ? data : data.slice((state.page - 1) * state.pageSize, state.page * state.pageSize);

// 4) 渲染表头(排序按钮)+ 筛选行
let html = '<table class="table"><thead><tr>';
Expand DownExpand Up@@ -1606,8 +1636,11 @@
// 5) 分页器 + 每页行数
if (pages > 1) {
html += '<div class="pager">';
for (let i = 1; i <= pages; i++) html += '<button type="button" class="' + (i === state.page ? "active" : "") + '" data-p="' + i + '">' + i + "</button>";
html += "<span>" + state.page + " / " + pages + " · " + T("tx.pager.count", { n: data.length }) + "</span></div>";
pagerButtons(state.page, pages).forEach((p) => {
if (p === "…") html += '<span class="pager-ellipsis">…</span>';
else html += '<button type="button" class="' + (p === state.page ? "active" : "") + '" data-p="' + p + '">' + p + "</button>";
});
html += "<span>" + state.page + " / " + pages + " · " + T("tx.pager.count", { n: totalRows }) + "</span></div>";
}
html += '<div class="pager-size">' + T("tx.pager.size") + ' <select data-page-size><option value="5">5</option><option value="10">10</option><option value="25">25</option><option value="50">50</option></select> ' + T("tx.pager.rows") + '</div>';

Expand Down
Loading