chore: 完成全量功能迭代与部署准备

- 移除冗余依赖包
- 新增账号禁用校验与用户管理能力
- 新增文档下载与管理页面文件展示
- 新增API文档页面与用户管理前端页面
- 重构时区处理与docker-compose部署配置
- 完善测试用例与项目文档
This commit is contained in:
2026-08-01 00:02:42 +08:00
parent f92eff6f65
commit 6c6f690788
19 changed files with 2000 additions and 485 deletions
+163 -9
View File
@@ -5,11 +5,11 @@
2. 五区块可识别标记(文案与 section id)
3. 零外部依赖:无 http(s) 外链资源、无 CDN 引用
4. fetch 调用路径与后端 API 契约一致(含 /api/v1/auth/*
5. 删除操作的 confirm() 二次确认逻辑
5. 删除/重置操作的通用 overlay 弹窗组件(替换原生 prompt/confirm
6. 登录门禁:登录卡片、localStorage key、/auth/me 验证、/auth/login 路径
7. 顶栏用户区:用户名、角色徽章、修改密码、退出登录
8. 修改密码:旧/新/确认表单、must_change_password 强制改密
9. 用户管理区块:列表/创建表单/角色下拉/重置/删除 confirm、admin 角色门禁
9. 用户管理区块:列表/创建表单/角色下拉/重置密码弹窗/删除确认弹窗、admin 角色门禁
10. 请求拦截:Authorization Bearer 注入、1005 回登录、1006 错误条
11. API 指南区块:导航/section、API_GUIDE 清单与真实路由一致性、试一下面板、
curl 复制、auth 标注、upload 文件选择、禁止自定义 URL
@@ -140,9 +140,10 @@ def test_admin_page_ingest_polling(admin_html: str) -> None:
assert "disabled" in admin_html
def test_admin_page_has_confirm(admin_html: str) -> None:
"""删除操作包含 confirm() 二次确认逻辑"""
assert "confirm(" in admin_html
def test_admin_page_no_prompt_confirm_calls(admin_html: str) -> None:
"""清理:弹窗组件已替换原生 prompt/confirm,全页面无 prompt( 与 confirm( 调用残留"""
assert "prompt(" not in admin_html
assert "confirm(" not in admin_html
def test_admin_page_login_card(admin_html: str) -> None:
@@ -193,8 +194,52 @@ def test_admin_page_password_form(admin_html: str) -> None:
assert "passwordForced" in admin_html
def test_admin_page_profile_section(admin_html: str) -> None:
"""个人中心区块:导航按钮、section、账号信息卡片、改密表单、退出按钮、
user 角色默认进入、GET /auth/me 与 POST /auth/password 路径"""
# section 与导航按钮(不限 admin,所有登录用户可见)
assert 'id="section-profile"' in admin_html
assert 'id="nav-profile"' in admin_html
assert 'data-target="section-profile"' in admin_html
assert "个人中心" in admin_html
# 账号信息卡片字段:用户名 / 角色 / 创建时间 / 须改密 / 启用状态
assert 'id="profile-cards"' in admin_html
for label in ("用户名", "角色", "创建时间", "须改密", "启用状态"):
assert label in admin_html
# 改密表单:旧密码 / 新密码 / 确认 / 强度提示 / 提交按钮
assert 'id="profile-password-form"' in admin_html
assert 'id="profile-old-password"' in admin_html
assert 'id="profile-new-password"' in admin_html
assert 'id="profile-confirm-password"' in admin_html
assert 'id="profile-strength-hint"' in admin_html
assert 'id="btn-profile-password-submit"' in admin_html
# 强度提示复用 Task 3 文案(<8 弱 / ≥8 中 / ≥12 强)
assert "密码强度:" in admin_html
for level in ("", "", ""):
assert level in admin_html
# 两次不一致本地拦截
assert "两次输入的新密码不一致" in admin_html
# 提交按钮 loading 态
assert "提交中…" in admin_html
# 退出登录按钮(复用现有 logout 逻辑)
assert 'id="btn-profile-logout"' in admin_html
assert "退出登录" in admin_html
assert "doLogout" in admin_html
# 数据来源:GET /auth/me 加载账号信息;POST /auth/password 改密
assert "/api/v1/auth/me" in admin_html
assert "/api/v1/auth/password" in admin_html
# 个人中心加载与渲染函数
assert "loadProfile" in admin_html
assert "renderProfile" in admin_html
# user 角色默认进个人中心(admin 仍默认进概览)
assert 'activateSection("section-profile")' in admin_html
assert 'activateSection("section-overview")' in admin_html
# activateSection 触发 loadProfile
assert 'targetId === "section-profile"' in admin_html
def test_admin_page_users_section(admin_html: str) -> None:
"""用户管理区块:用户列表/创建表单/角色下拉/重置密码/删除 confirm/角色门禁"""
"""用户管理区块:用户列表/创建表单/角色下拉/重置密码弹窗/删除确认弹窗/角色门禁"""
assert 'id="section-users"' in admin_html
assert 'id="users-tbody"' in admin_html
# 表头列:用户名/角色/须改密/创建时间/操作
@@ -208,10 +253,10 @@ def test_admin_page_users_section(admin_html: str) -> None:
assert '<option value="admin"' in admin_html
assert '<option value="user"' in admin_html
assert "创建用户" in admin_html
# 操作列:重置密码(弹输入)与删除(confirm 二次确认
# 操作列:重置密码 + 删除均走通用弹窗组件(无 prompt/confirm 调用
assert "重置密码" in admin_html
assert "prompt(" in admin_html
assert "确定删除用户" in admin_html
assert "resetUserPassword" in admin_html
assert "deleteUser" in admin_html
# 用户管理端点
assert "/api/v1/auth/users" in admin_html
# 角色门禁:仅 admin 挂载该区块进 DOM,非 admin 完全不渲染
@@ -220,6 +265,115 @@ def test_admin_page_users_section(admin_html: str) -> None:
assert "unmountUsersSection" in admin_html
def test_admin_page_users_filter_and_inline_edit(admin_html: str) -> None:
"""用户管理:列表搜索筛选 + 行内角色编辑 + 启用开关 + 当前 admin 自身行防降级"""
# 列表搜索筛选:用户名搜索框 + 角色筛选下拉
assert 'id="user-search"' in admin_html
assert 'id="user-role-filter"' in admin_html
assert '<option value="all"' in admin_html
# 输入/变更事件触发本地过滤(不重新请求后端)
assert 'addEventListener("input", applyUsersFilter)' in admin_html
assert 'addEventListener("change", applyUsersFilter)' in admin_html
assert "applyUsersFilter" in admin_html
# 表头加「启用」列
assert "启用" in admin_html
# 行内角色编辑:select + 保存按钮(仅当值改变时启用)
assert "user-role-select" in admin_html
assert "user-role-save" in admin_html
assert "updateUserRole" in admin_html
# 行内启用/禁用开关:按钮文字 + 样式区分
assert "user-enabled-toggle" in admin_html
assert "toggleUserEnabled" in admin_html
# PATCH /auth/users/{username} 端点调用(role 与 enabled 两条分支)
assert 'method: "PATCH"' in admin_html
assert "encodeURIComponent(username)" in admin_html
# 当前登录 admin 自身行防自锁降级:role select disabled + 启用开关 disabled
assert "isSelf" in admin_html
assert "不能禁用当前登录账号" in admin_html
def test_admin_page_modal_component(admin_html: str) -> None:
"""通用 overlay 弹窗组件:modal-overlay/modal-card 结构 + openModal/closeModal API"""
# CSS 类
assert "modal-overlay" in admin_html
assert "modal-card" in admin_html
assert "modal-title" in admin_html
assert "modal-content" in admin_html
assert "modal-actions" in admin_html
# 挂载点容器
assert 'id="modal-root"' in admin_html
# 通用 JS API
assert "function openModal(" in admin_html
assert "function closeModal(" in admin_html
assert "function isModalSubmitting(" in admin_html
assert "function setModalSubmitting(" in admin_html
assert "function showModelError(" in admin_html
assert "function hideModelError(" in admin_html
# 提交中标记属性
assert "data-submitting" in admin_html
def test_admin_page_modal_cancel_and_loading(admin_html: str) -> None:
"""弹窗可取消(点遮罩/取消按钮/ESC)+ 提交中不可取消 + loading 态(提交中禁用)"""
# 点遮罩关闭:e.target === overlay
assert "e.target === overlay" in admin_html
# 取消按钮存在
assert "取消" in admin_html
# ESC 键关闭最顶层弹窗
assert "Escape" in admin_html
# 提交中不可关闭:遮罩点击与 ESC 均检查 data-submitting !== "true"
assert 'data-submitting") !== "true"' in admin_html
assert 'data-submitting") === "true"' in admin_html
# 提交 loading 文案 + 按钮禁用
assert "提交中…" in admin_html
assert 'submitBtn.disabled = true' in admin_html
# isModalSubmitting 守卫:取消按钮在提交中不响应
assert "isModalSubmitting(" in admin_html
def test_admin_page_reset_password_modal(admin_html: str) -> None:
"""重置密码弹窗:新密码/确认/强度提示/两次不一致本地拦截/loading 态"""
# 弹窗标题含用户名占位
assert "重置用户" in admin_html
assert "密码" in admin_html
# 新密码 + 确认密码输入框(动态创建,id 经 JS 属性赋值)
assert 'newInput.id = "modal-reset-new"' in admin_html
assert 'confirmInput.id = "modal-reset-confirm"' in admin_html
# 密码强度提示节点
assert 'hint.id = "modal-reset-strength"' in admin_html
assert "modal-strength-hint" in admin_html
# 强度三档纯文案:<8 弱 / ≥8 中 / ≥12 强
assert "密码强度:" in admin_html
for level in ("", "", ""):
assert level in admin_html
# 两次不一致本地拦截
assert "两次输入的新密码不一致" in admin_html
# 重置密码端点
assert "/api/v1/auth/users/" in admin_html
assert "/password" in admin_html
# 提交按钮 loading 态
assert "setModalSubmitting" in admin_html
def test_admin_page_delete_user_modal(admin_html: str) -> None:
"""删除确认弹窗:警告文案 + 输入用户名匹配才可提交 + loading 态"""
# 弹窗标题
assert "删除用户" in admin_html
# 警告文案
assert "此操作不可恢复,将清除该用户及其全部会话" in admin_html
# 「请输入用户名 {username} 以确认」+ 文本输入框(动态创建,id 经 JS 属性赋值)
assert "请输入用户名" in admin_html
assert "以确认" in admin_html
assert 'input.id = "modal-delete-input"' in admin_html
# 输入 !== username 时删除按钮禁用;匹配后启用
assert "submitBtn.disabled = true" in admin_html
assert "input.value !== username" in admin_html
# 删除端点
assert 'method: "DELETE"' in admin_html
# 提交按钮 loading 态
assert "setModalSubmitting" in admin_html
def test_admin_page_auth_interceptor(admin_html: str) -> None:
"""请求拦截:统一注入 Authorization Bearer1005 回登录;1006 错误条提示"""
assert 'options.headers["Authorization"] = "Bearer " + token' in admin_html