Files
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

50 lines
2.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
import io
p = '/opt/dshs/web/admin.html'
s = io.open(p, encoding='utf-8').read()
anchor = """ <table class="admin">
<thead><tr><th>用户名</th><th>角色</th><th>注册时间</th><th>操作</th></tr></thead>
<tbody id="users"></tbody>
</table>
"""
assert anchor in s
block = anchor + """
<h3 style="margin:22px 0 8px">存储用量 <span class="auth-sub" id="storageAt" style="font-weight:400"></span></h3>
<table class="admin">
<thead><tr><th>用户</th><th>工作区</th><th>会话</th><th>回收站</th><th>可清理</th></tr></thead>
<tbody id="storage"></tbody>
</table>
<p class="auth-sub" style="margin:6px 0 0">工作区达 <span id="thWs"></span> / 会话达 <span id="thSess"></span> 时由每日维护任务自动清理(工作区 90 天、会话 365 天前的记录;均先入回收站保留 30 天)。</p>
"""
s = s.replace(anchor, block, 1)
js_anchor = " document.getElementById('logoutBtn').addEventListener('click', async () => {"
assert js_anchor in s
js = """ function fmtB(b) { return b >= 1073741824 ? (b / 1073741824).toFixed(2) + ' GB' : (b / 1048576).toFixed(1) + ' MB' }
async function loadStorage() {
const tbody = document.getElementById('storage')
try {
const r = await (await fetch('/api/admin/storage')).json()
document.getElementById('storageAt').textContent = r.generatedAt ? `(更新于 ${new Date(r.generatedAt).toLocaleString()})` : ''
if (r.thresholds) {
document.getElementById('thWs').textContent = r.thresholds.wsMB + ' MB'
document.getElementById('thSess').textContent = r.thresholds.sessionsMB + ' MB'
}
tbody.innerHTML = (r.users ?? []).map((u) => `<tr>
<td>${esc(u.username)}</td>
<td style="${u.wsOver ? 'color:var(--danger)' : ''}">${fmtB(u.ws)}</td>
<td style="${u.sessionsOver ? 'color:var(--danger)' : ''}">${fmtB(u.sessions)}</td>
<td>${fmtB(u.trash)}</td>
<td>${u.cleanableT1 + u.cleanableT2} 项 / ${fmtB(u.cleanableBytes)}</td>
</tr>`).join('') || `<tr><td colspan="5" class="auth-sub">${esc(r.note ?? '暂无数据')}</td></tr>`
} catch { tbody.innerHTML = '<tr><td colspan="5" class="auth-sub">读取失败</td></tr>' }
}
""" + js_anchor
s = s.replace(js_anchor, js, 1)
call_anchor = " await loadUsers()"
if call_anchor in s:
s = s.replace(call_anchor, call_anchor + "\n await loadStorage()", 1)
else:
s = s.replace("loadUsers()", "loadUsers(); loadStorage()", 1)
io.open(p, 'w', encoding='utf-8', newline='').write(s)
print('E admin.html 用量区块已写入')