Appearance
面板概览与导航
本文引用的文件
目录
- 简介
- 项目结构与职责划分
- 核心组件:管理面板外壳
- 架构总览
- 菜单结构说明
- 页面初始化流程
- URL、路由与深度链接
- 前端到后端接口映射
- 权限控制与未授权处理
- 常见使用场景
- 多语言文案在面板中的使用方式
- 故障排查与常见问题
- 结论
简介
本文面向管理员和前端维护者,解释 SkinNexus 管理面板的工作方式:AdminPanel.vue 如何根据当前用户角色、站点配置和插件能力决定左侧菜单;前端 adminApi.js 如何把管理视图的数据请求统一发送到 /api/admin/v1/*;后端 adminapi.go 如何通过会话或令牌校验权限并暴露具体端点。文档还覆盖仪表盘、用户、玩家/角色、材质、插件、主题市场、设置、审计、报告、Union、状态等模块的职责边界,以及站长登录、跳转到用户列表、查看诊断信息等典型流程。
项目结构与职责划分
管理面板涉及三层代码:
- 前端外壳:
AdminPanel.vue负责侧边栏、子视图切换、深度链接和权限态展示。 - 前端数据层:
adminApi.js提供带管理员令牌注入的统一请求函数。 - 后端接口层:
adminapi.go注册/api/admin/v1/*路由,实现会话/令牌鉴权、业务聚合和分页响应。
图表来源
章节来源
核心组件:管理面板外壳
AdminPanel.vue 是管理面板的容器,不直接承载所有业务逻辑,而是:
- 定义静态菜单项,包括仪表盘、用户、玩家、邀请码、设置、状态、访问日志、举报、材质、审计、任务队列、Union、插件和市场。
- 根据站点配置隐藏可选菜单:当站点未启用邀请码时隐藏“邀请码”;未启用 Union 时隐藏“Union”。
- 根据插件 UI 注册表动态追加插件菜单项。
- 根据当前 URL 同步激活的标签页,并渲染对应的子视图组件。
- 在未通过会话或令牌验证前,只显示侧边栏和管理员令牌输入框,避免每个子视图反复触发 403。
关键行为包括:
visibleNav根据invite_required和union_enabled过滤菜单。go(id)切换到内置菜单项。openPlugin(path)切换到插件页面。ready控制主内容区域是否渲染子视图。reloadTick通过 key 变更强制重新挂载当前视图,从而触发其自身的数据加载。
章节来源
架构总览
管理面板采用“外壳 + 子视图 + 共享 API 客户端”的分层模式:
图表来源
菜单结构说明
AdminPanel 的菜单由三部分构成:内置菜单、站点标志位过滤、插件扩展菜单。
| 菜单项 | 内部 id | 主要职责 | 可见性条件 |
|---|---|---|---|
| 仪表盘 | dashboard | 展示用户数、角色数、材质数、弱哈希余量、存储用量、签名密钥指纹 | 始终可见 |
| 用户管理 | users | 查询、重置密码、修改邮箱昵称、调整权限、删除用户 | 始终可见 |
| 角色管理 | players | 管理站长的玩家/角色列表、改名、改所有者、替换材质、删除 | 始终可见 |
| 邀请码 | invitation | 生成、编辑、列出邀请码 | 仅当站点启用邀请码时可见 |
| 站点设置 | settings | 获取和保存站点配置项 | 始终可见 |
| 运行状态 | status | 展示版本、构建信息、运行时环境、数据库信息和模块开关 | 始终可见 |
| 访问日志 | access | 分页查看网页、启动器、Yggdrasil、Union 访问记录 | 始终可见 |
| 举报处理 | reports | 列出举报、处理举报 | 始终可见 |
| 材质库 | textures | 查询、审核、打击、删除材质 | 始终可见 |
| 操作审计 | audit | 按操作人、动作、关键词查询后台审计日志 | 始终可见 |
| 任务队列 | jobs | 列出任务、查看详情、取消或恢复任务 | 始终可见 |
| Union | union | 联盟状态、轮换、黑名单、诊断等操作 | 仅当站点启用 Union 时可见 |
| 插件 | plugins | 查看已安装插件、回滚、卸载、配置、绕过守卫 | 始终可见 |
| 插件市场 | market | 浏览市场目录、安装插件、上传插件包 | 始终可见 |
此外,插件可通过 pluginUI.js 注册管理面板扩展页面,这些扩展会出现在侧边栏中,并根据插件声明的权限要求过滤。
章节来源
页面初始化流程
管理面板的初始化不是单一函数调用,而是由外层应用、面板外壳和子视图共同完成:
外层判断管理员身份
App.vue从/api/v1/me获取当前用户对象,并通过user.permission > 0判断是否为管理员。只有管理员才会看到“管理面板”入口。进入面板后加载初始状态
AdminPanel.vue在onMounted中执行以下工作:- 如果当前会话已经是管理员(
permission > 0),则不再需要机器令牌。 - 加载插件 UI 中声明的管理面板页面,并按当前权限过滤。
- 尝试加载站点配置标志位,用于决定是否显示邀请码和 Union 菜单。
- 如果没有会话管理员且没有本地存储的管理员令牌,则
ready保持为假,只显示令牌输入区。
- 如果当前会话已经是管理员(
渲染左侧导航 模板遍历
visibleNav,用 i18n 的t()渲染菜单标题,并渲染插件扩展菜单。加载目标视图数据 当
ready为真时,面板渲染当前组件。每个子视图通常在自己的onMounted中发起数据请求;面板通过reloadTick改变 key 来重新挂载当前视图,从而实现刷新。
图表来源
章节来源
URL、路由与深度链接
管理面板支持浏览器地址栏深度链接,使刷新、分享和后退按钮能回到上次打开的标签页。
/admin:默认仪表盘。/admin/users:用户管理。/admin/players:角色管理。/admin/textures:材质库。/admin/settings:站点设置。/admin/status:运行状态。/admin/access:访问日志。/admin/reports:举报处理。/admin/audit:操作审计。/admin/jobs:任务队列。/admin/union:Union。/admin/plugins:插件。/admin/market:插件市场。/admin/plugin/<path>:插件扩展页面。
面板内部通过监听 current 和 currentPlugin 的变化写入 history.pushState,同时监听 popstate 以支持后退。未知路径会回退到仪表盘,而不是报错。
图表来源
章节来源
前端到后端接口映射
adminApi.js 是管理面板统一的 HTTP 客户端。它的主要职责不是定义每个业务端点,而是:
- 从本地存储读取
X-Admin-Token。 - 给每次请求添加该头部。
- 将网络超时、非成功状态码转换为带
status的错误对象。 - 遇到 401 或 403 时,将
needToken设为真,让面板外壳显示令牌输入区。
后端在 adminapi.go 中集中注册 /api/admin/v1/* 路由。前端各子视图根据业务语义调用不同路径,例如:
- 仪表盘统计:
GET /api/admin/v1/overview - 运行状态:
GET /api/admin/v1/status - 部署自检:
GET /api/admin/v1/diagnostics - 用户列表:
GET /api/admin/v1/users - 材质列表:
GET /api/admin/v1/textures - 审计日志:
GET /api/admin/v1/audit - 访问日志:
GET /api/admin/v1/access-logs - 举报列表和处理:
GET /api/admin/v1/reports、POST /api/admin/v1/reports/{id}/resolve - 站点设置:
GET /api/admin/v1/settings、PUT /api/admin/v1/settings - Union 相关:
GET /api/admin/v1/union/status及一系列运维操作端点 - 插件与市场:
GET /api/admin/v1/plugins、GET /api/admin/v1/market/catalog、POST /api/admin/v1/market/install、POST /api/admin/v1/market/upload
图表来源
章节来源
权限控制与未授权处理
权限控制分为两层:前端判断是否显示入口,后端对每个管理接口做最终鉴权。
前端权限
App.vue使用/api/v1/me返回的permission字段判断管理员。普通用户不会看到“管理面板”入口。AdminPanel.vue进一步区分两种情况:- 会话管理员:
permission > 0,可直接进入面板,无需手动粘贴令牌。 - 非会话管理员:需要填写
X-Admin-Token,面板才会把ready设为真。
- 会话管理员:
后端权限
adminapi.go 的鉴权逻辑允许两种方式:
- 管理员网页会话:Cookie 携带站点会话,服务器查得用户且
permission > 0。 - 管理员令牌:请求头
X-Admin-Token与后端环境变量SKIN_ADMIN_TOKEN常量比较。
如果两者都不满足,后端返回 403,错误消息指向“管理员令牌无效或未登录”。对于尚未完成邮箱验证但具有管理员权限的会话,后端还会拒绝可写操作,提示必须先完成邮箱验证。
图表来源
未授权跳转与空菜单
- 前端不会因 401/403 自动跳转到登录页,而是通过
adminApi.js把needToken置为真,让AdminPanel.vue显示令牌输入区。 - 如果站点关闭了邀请码,邀请码菜单会被隐藏;如果关闭了 Union,Union 菜单被隐藏。
- 如果所有菜单都被隐藏,面板仍会渲染外壳,但左侧导航为空。此时应检查站点配置和插件权限,而不是假设后端一定出错。
章节来源
常见使用场景
场景一:站长登录后进入仪表盘
- 站长通过正常登录获得会话。
App.vue发现permission > 0,显示管理面板入口。- 进入
/admin后,AdminPanel.vue检测到会话管理员,跳过令牌输入。 - 仪表盘视图加载
/api/admin/v1/overview,显示用户、角色、材质、弱哈希余量等统计。
章节来源
场景二:跳转到用户列表
- 管理员点击“用户管理”。
AdminPanel.vue更新current为users,并渲染UsersView。- 用户视图发起
GET /api/admin/v1/users。 - 后端返回分页用户列表,包含总数和当前页码。
章节来源
场景三:查看诊断信息
- 管理员进入“运行状态”或相关诊断页面。
- 前端调用
/api/admin/v1/status或/api/admin/v1/diagnostics。 - 后端返回版本、Go 版本、数据库引擎、迁移版本、容器信息、运行时间、模块开关等部署事实。
章节来源
多语言文案在面板中的使用方式
面板的多语言由 Vue I18n 驱动,i18n.js 负责选择语言并持久化到 cookie 和本地存储。管理面板中的菜单标题和部分提示使用 useI18n().t() 渲染。
中文文案集中在 zh-CN.json,英文文案在 en.json。面板相关键包括:
admin.title:管理面板标题。admin.tokenPlaceholder:令牌输入框占位符。admin.load:加载按钮文案。admin.reload:刷新按钮文案。admin.navDashboard:仪表盘。admin.navUsers:用户管理。admin.navPlayers:角色管理。admin.navSettings:站点设置。admin.navStatus:运行状态。admin.navAccess:访问日志。admin.navReports:举报处理。admin.navTextures:材质库。admin.navAudit:操作审计。admin.navJobs:任务队列。admin.navUnion:Union。admin.navPlugins:插件。admin.navMarket:插件市场。
新增或修改菜单文案时,应同步更新中英文翻译文件,并确保 AdminPanel.vue 使用的 labelKey 与翻译键一致。
章节来源
故障排查与常见问题
| 现象 | 可能原因 | 排查建议 |
|---|---|---|
| 登录后看不到管理面板入口 | 用户 permission 不大于 0 | 检查 /api/v1/me 返回的权限字段 |
| 进入面板后只显示令牌输入框 | 会话不是管理员,也没有本地存储的管理员令牌 | 确认已用管理员账号登录,或在令牌框填入 SKIN_ADMIN_TOKEN |
| 点击菜单无反应 | URL 路径不存在或匹配不到内置菜单 | 检查地址栏是否为 /admin/<id>,未知路径会回退到仪表盘 |
| 邀请码菜单不出现 | 站点未启用邀请码 | 检查站点配置 invite_required |
| Union 菜单不出现 | 站点未启用 Union | 检查站点配置 union_enabled |
| 接口返回 401 或 403 | 令牌无效、会话失效、或非管理员 | 清除本地令牌重试,或用管理员会话重新登录 |
| 审计或设置操作报需邮箱验证 | 管理员账号未完成邮箱验证 | 先完成邮箱验证,再执行敏感操作 |
| 刷新后视图丢失 | 深度链接未正确写入或 URL 被改写 | 检查 /admin 或 /admin/<id> 是否正确 |
| 插件菜单不显示 | 插件未注册、权限不足或被过滤 | 检查插件 UI 注册表和当前用户权限 |
章节来源
结论
管理面板的核心设计是“前端外壳负责导航与可见性,后端负责鉴权与数据”。AdminPanel.vue 根据会话权限、站点配置和插件能力组合出最终菜单;adminApi.js 把管理请求统一带上管理员令牌;adminapi.go 在 /api/admin/v1/* 上实现细粒度后端权限控制。理解这三层关系后,可以安全地扩展新菜单、对接新接口,并在权限、语言和深度链接方面保持一致行为。