chore: 完成全量功能迭代与部署准备
- 移除冗余依赖包 - 新增账号禁用校验与用户管理能力 - 新增文档下载与管理页面文件展示 - 新增API文档页面与用户管理前端页面 - 重构时区处理与docker-compose部署配置 - 完善测试用例与项目文档
This commit is contained in:
+163
-9
@@ -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 Bearer;1005 回登录;1006 错误条提示"""
|
||||
assert 'options.headers["Authorization"] = "Bearer " + token' in admin_html
|
||||
|
||||
Reference in New Issue
Block a user