权限菜单(二):前端菜单改为按角色权限渲染 #138

Closed
opened 2026-08-28 17:42:49 +08:00 by ila · 4 comments
Owner

所属与来源

  • 关联工单:#137 GoAuto 模块写入系统菜单(前置)、#62 AI 匹配设置。
  • 来源:用户于 2026-08-28 反馈 Admin 的采集采购模块未纳入菜单管理、角色编辑无法选择菜单,并要求区分采购员与管理员的可见范围。#137 解决菜单入库与角色绑定,本工单解决前端按权限渲染。
  • 类型:Admin 前端 / 菜单渲染方式改造。
  • 设计证据:菜单项本身、图标与文案均不变,仅按角色隐藏部分模块;属现有导航的可见性调整。用户于 2026-08-28 确认 v1 标注原型:https://git.ilapage.cn/attachments/0d1e252a-e463-4b28-8520-58e54b1d9b16;覆盖角色菜单配置、管理员/采购员菜单、未授权 URL 与无菜单权限状态。
  • 工具回退说明:本工单通过 Gitea API 创建;当前会话未提供 Gitea MCP 工具,按 AGENTS.md「Gitea 交互与工单最小读取」记录回退原因。

当前事实(提交 30d8238 复核)

  • GoAuto 全部模块位于 web/src/router/index.js 的 constantRoutes(第 38~245 行;asyncRoutes 自 246 行起)。
  • constantRoutes 对所有登录用户可见,不做角色过滤,也不读取后端菜单。
  • 因此采购员当前能看到全部 GoAuto 菜单,包括应当硬隐藏的 AI 规格匹配;点击后部分 API 被 casbin 拒绝,形成「看得见、点不动」的割裂。按 #137 与当前业务规则,采购员默认可见“SYB 店铺”的只读页面,但新增、改名、启停、删除和发现操作仍仅管理员可执行;角色管理员可以取消该菜单。
  • 前端已有 permission.js 的 generateRoutes(web/src/store/modules/permission.js:140)用于按权限生成路由,现有 asyncRoutes 走该路径。

目标

  1. GoAuto 模块的菜单可见性由后端决定,采购员只看到其被授权的模块。
  2. 管理员可见全部模块,行为与现在一致。
  3. 在角色编辑页调整采购员菜单勾选后,重新登录即生效,无需改代码或发版。

非目标

  • 不修改任何页面内部的功能与布局,仅改变导航可见性。
  • 不新增或重命名菜单项、不改图标与文案。
  • 不修改后端权限矩阵与 casbin 策略(#137 范围)。
  • 不改造非 GoAuto 的既有菜单与路由。

实施方案

  1. 将 GoAuto 相关路由从 constantRoutes 迁出,纳入按权限生成的路由集合,复用既有 generateRoutes 机制,不新造第二套菜单渲染逻辑。
  2. 路由的 path 与 name 必须与 #137 写入 sys_menu 的记录逐条严格一致——不一致会导致菜单点不动或白屏。建议以脚本或测试比对,不靠人工核对。
  3. 用户无任何 GoAuto 菜单权限时,页面不应白屏或报错;按既有的无权限处理方式呈现。
  4. 直接输入 URL 访问未授权模块时,沿用既有的前端拦截方式;API 层的 casbin 仍是最终防线,前端拦截不得被当作安全措施。
  5. 登录后菜单按后端返回结果渲染;角色菜单调整后重新登录即生效。是否需要即时刷新(不重登)不在本工单范围。

安全边界

  • 前端可见性调整不构成安全边界;越权防护仍由后端 casbin 承担,本工单不得削弱。
  • AI 匹配设置对采购员不可见,与 #137 的硬约束一致;即使前端出现异常也不得渲染该入口。
  • 不在前端存储或展示任何 API Key、令牌与凭据。

验收标准

  • 采购员登录后只看到其被授权的 GoAuto 模块;AI 规格匹配始终不出现。SYB 店铺按角色菜单勾选决定是否出现,出现时仍只具备 #137 规定的只读能力。
  • 管理员登录后可见全部 GoAuto 模块,与本工单实施前一致。
  • 在角色编辑页调整采购员菜单勾选并重新登录后,菜单随之变化,无需改代码。
  • 路由 path / name 与 sys_menu 记录逐条一致(以比对脚本或测试佐证)。
  • 采购员直接输入未授权模块 URL 时被前端拦截,且后端 API 仍返回拒绝。
  • 无 GoAuto 菜单权限的用户登录不白屏、不报错。
  • 非 GoAuto 的既有菜单与路由行为无任何变化。
  • 各页面内部功能与布局未发生变化。

验证方式

  • 前端构建与既有 Web 测试通过。
  • 分别以管理员与采购员账号登录,逐一核对菜单可见性。
  • 调整角色菜单勾选后重新登录,验证生效。
  • 路由与菜单记录的一致性比对。
  • 未覆盖的浏览器与异常路径如实回写。

依赖、并行与风险

  • 前置依赖 #137:菜单记录与角色绑定就绪后方可实施,否则前端拿不到菜单会全部空白。
  • 风险:路由与菜单记录不一致导致菜单不可用。缓解:第 2 项的严格一致要求与自动比对。
  • 风险:迁出 constantRoutes 后,若后端菜单接口异常会导致导航空白。缓解:第 3 项要求的无权限/异常呈现方式,并在验收中覆盖。
  • 回退:还原本工单提交即可恢复静态路由;#137 写入的菜单数据不受影响。

文档影响

  • Wiki Architecture-and-Code-Map:前端菜单由静态路由改为按后端菜单渲染。
  • Wiki Local-Development-and-Verification:如本地验证方式因菜单来源变化而调整,需同步更新;无变化则在工单说明。
  • 按 Wiki-first 门禁:如需更新,先改线上页面并回读 revision,再执行一轮 sync 与一轮 sync --check,把页面与 revision 写回本工单。

状态

验收通过(用户于 2026-08-28 明确确认;实现提交 5feb4e8)。

## 所属与来源 - 关联工单:#137 GoAuto 模块写入系统菜单(前置)、#62 AI 匹配设置。 - 来源:用户于 2026-08-28 反馈 Admin 的采集采购模块未纳入菜单管理、角色编辑无法选择菜单,并要求区分采购员与管理员的可见范围。#137 解决菜单入库与角色绑定,本工单解决**前端按权限渲染**。 - 类型:Admin 前端 / 菜单渲染方式改造。 - 设计证据:菜单项本身、图标与文案均不变,仅按角色隐藏部分模块;属现有导航的可见性调整。用户于 2026-08-28 确认 v1 标注原型:https://git.ilapage.cn/attachments/0d1e252a-e463-4b28-8520-58e54b1d9b16;覆盖角色菜单配置、管理员/采购员菜单、未授权 URL 与无菜单权限状态。 - 工具回退说明:本工单通过 Gitea API 创建;当前会话未提供 Gitea MCP 工具,按 `AGENTS.md`「Gitea 交互与工单最小读取」记录回退原因。 ## 当前事实(提交 30d8238 复核) - GoAuto 全部模块位于 `web/src/router/index.js` 的 `constantRoutes`(第 38~245 行;`asyncRoutes` 自 246 行起)。 - `constantRoutes` 对所有登录用户可见,**不做角色过滤,也不读取后端菜单**。 - 因此采购员当前能看到全部 GoAuto 菜单,包括应当硬隐藏的 AI 规格匹配;点击后部分 API 被 casbin 拒绝,形成「看得见、点不动」的割裂。按 #137 与当前业务规则,采购员默认可见“SYB 店铺”的只读页面,但新增、改名、启停、删除和发现操作仍仅管理员可执行;角色管理员可以取消该菜单。 - 前端已有 `permission.js` 的 `generateRoutes`(`web/src/store/modules/permission.js:140`)用于按权限生成路由,现有 `asyncRoutes` 走该路径。 ## 目标 1. GoAuto 模块的菜单可见性由后端决定,采购员只看到其被授权的模块。 2. 管理员可见全部模块,行为与现在一致。 3. 在角色编辑页调整采购员菜单勾选后,**重新登录即生效**,无需改代码或发版。 ## 非目标 - 不修改任何页面内部的功能与布局,仅改变导航可见性。 - 不新增或重命名菜单项、不改图标与文案。 - 不修改后端权限矩阵与 casbin 策略(#137 范围)。 - 不改造非 GoAuto 的既有菜单与路由。 ## 实施方案 1. 将 GoAuto 相关路由从 `constantRoutes` 迁出,纳入按权限生成的路由集合,复用既有 `generateRoutes` 机制,**不新造第二套菜单渲染逻辑**。 2. 路由的 `path` 与 `name` 必须与 #137 写入 `sys_menu` 的记录**逐条严格一致**——不一致会导致菜单点不动或白屏。建议以脚本或测试比对,不靠人工核对。 3. 用户无任何 GoAuto 菜单权限时,页面不应白屏或报错;按既有的无权限处理方式呈现。 4. 直接输入 URL 访问未授权模块时,沿用既有的前端拦截方式;**API 层的 casbin 仍是最终防线**,前端拦截不得被当作安全措施。 5. 登录后菜单按后端返回结果渲染;角色菜单调整后重新登录即生效。是否需要即时刷新(不重登)不在本工单范围。 ## 安全边界 - 前端可见性调整**不构成安全边界**;越权防护仍由后端 casbin 承担,本工单不得削弱。 - AI 匹配设置对采购员不可见,与 #137 的硬约束一致;即使前端出现异常也不得渲染该入口。 - 不在前端存储或展示任何 API Key、令牌与凭据。 ## 验收标准 - [ ] 采购员登录后只看到其被授权的 GoAuto 模块;AI 规格匹配始终不出现。SYB 店铺按角色菜单勾选决定是否出现,出现时仍只具备 #137 规定的只读能力。 - [ ] 管理员登录后可见全部 GoAuto 模块,与本工单实施前一致。 - [ ] 在角色编辑页调整采购员菜单勾选并重新登录后,菜单随之变化,无需改代码。 - [ ] 路由 `path` / `name` 与 `sys_menu` 记录逐条一致(以比对脚本或测试佐证)。 - [ ] 采购员直接输入未授权模块 URL 时被前端拦截,且后端 API 仍返回拒绝。 - [ ] 无 GoAuto 菜单权限的用户登录不白屏、不报错。 - [ ] 非 GoAuto 的既有菜单与路由行为无任何变化。 - [ ] 各页面内部功能与布局未发生变化。 ## 验证方式 - 前端构建与既有 Web 测试通过。 - 分别以管理员与采购员账号登录,逐一核对菜单可见性。 - 调整角色菜单勾选后重新登录,验证生效。 - 路由与菜单记录的一致性比对。 - 未覆盖的浏览器与异常路径如实回写。 ## 依赖、并行与风险 - **前置依赖 #137**:菜单记录与角色绑定就绪后方可实施,否则前端拿不到菜单会全部空白。 - 风险:路由与菜单记录不一致导致菜单不可用。缓解:第 2 项的严格一致要求与自动比对。 - 风险:迁出 `constantRoutes` 后,若后端菜单接口异常会导致导航空白。缓解:第 3 项要求的无权限/异常呈现方式,并在验收中覆盖。 - 回退:还原本工单提交即可恢复静态路由;#137 写入的菜单数据不受影响。 ## 文档影响 - Wiki `Architecture-and-Code-Map`:前端菜单由静态路由改为按后端菜单渲染。 - Wiki `Local-Development-and-Verification`:如本地验证方式因菜单来源变化而调整,需同步更新;无变化则在工单说明。 - 按 Wiki-first 门禁:如需更新,先改线上页面并回读 revision,再执行一轮 `sync` 与一轮 `sync --check`,把页面与 revision 写回本工单。 ## 状态 验收通过(用户于 2026-08-28 明确确认;实现提交 `5feb4e8`)。
Author
Owner

#138 设计证据待确认(v1)

Gitea MCP 当前可用于工单评论,但未提供附件上传能力;本次仅附件上传按仓库规则回退 Gitea API,凭据由 Git Credential Manager 读取且未输出、未落库。

#138 前端菜单按角色权限渲染 v1

  • 版本:v1,2026-08-28;识别方式:图片右上角“待审核 · v1 · 2026-08-28”。
  • 覆盖:角色菜单勾选结果、管理员完整菜单、采购员重新登录后的授权菜单、采购员 AI 菜单硬排除、直接访问未授权 URL、无 GoAuto 菜单权限状态。
  • 复用:现有 go-admin 侧边栏、菜单图标、标题、选中态与页面布局;本工单只改变可见性,不新增组件、不改页面内部功能。
  • 交互:角色菜单调整后保存,用户重新登录生效;不要求登录中即时刷新。
  • 安全:前端隐藏不是安全边界,服务端 Casbin 仍作最终拒绝。

待确认的事实校正

工单正文验收项把“SYB 店铺管理”举为采购员应隐藏的管理员专属模块,但 #137 已实现代码及当前长期业务规则的权威事实是:

  • 采购员默认拥有“SYB 店铺”菜单和只读 API;
  • 新增、改名、启停、删除、发现店铺仍仅管理员可执行;
  • 角色管理员可以人工取消采购员的“SYB 店铺”菜单,重新登录后隐藏;
  • “AI 规格匹配”才是采购员不可勾选、始终隐藏的硬排除模块。

因此 v1 用“人工取消 SYB 店铺”的示例表达可配置性,不把该模块误画成采购员固定隐藏。用户确认 v1 后,将以此校正覆盖工单正文的冲突措辞再实施。

当前未修改 #138 生产代码,也未导出仓库内离线原型。

## #138 设计证据待确认(v1) Gitea MCP 当前可用于工单评论,但未提供附件上传能力;本次仅附件上传按仓库规则回退 Gitea API,凭据由 Git Credential Manager 读取且未输出、未落库。 ![#138 前端菜单按角色权限渲染 v1](https://git.ilapage.cn/attachments/0d1e252a-e463-4b28-8520-58e54b1d9b16) - 版本:v1,2026-08-28;识别方式:图片右上角“待审核 · v1 · 2026-08-28”。 - 覆盖:角色菜单勾选结果、管理员完整菜单、采购员重新登录后的授权菜单、采购员 AI 菜单硬排除、直接访问未授权 URL、无 GoAuto 菜单权限状态。 - 复用:现有 go-admin 侧边栏、菜单图标、标题、选中态与页面布局;本工单只改变可见性,不新增组件、不改页面内部功能。 - 交互:角色菜单调整后保存,用户重新登录生效;不要求登录中即时刷新。 - 安全:前端隐藏不是安全边界,服务端 Casbin 仍作最终拒绝。 ### 待确认的事实校正 工单正文验收项把“SYB 店铺管理”举为采购员应隐藏的管理员专属模块,但 #137 已实现代码及当前长期业务规则的权威事实是: - 采购员默认拥有“SYB 店铺”菜单和只读 API; - 新增、改名、启停、删除、发现店铺仍仅管理员可执行; - 角色管理员可以人工取消采购员的“SYB 店铺”菜单,重新登录后隐藏; - “AI 规格匹配”才是采购员不可勾选、始终隐藏的硬排除模块。 因此 v1 用“人工取消 SYB 店铺”的示例表达可配置性,不把该模块误画成采购员固定隐藏。用户确认 v1 后,将以此校正覆盖工单正文的冲突措辞再实施。 当前未修改 #138 生产代码,也未导出仓库内离线原型。
Author
Owner

设计确认并开始实施

用户于 2026-08-28 明确确认 #138 v1 原型通过。

  • 设计证据:https://git.ilapage.cn/attachments/0d1e252a-e463-4b28-8520-58e54b1d9b16
  • 版本识别:图片右上角“待审核 · v1 · 2026-08-28”
  • 确认人:需求方用户
  • 确认范围:角色菜单勾选结果、管理员完整菜单、采购员重新登录后的授权菜单、AI 菜单硬排除、未授权 URL、无 GoAuto 菜单权限。
  • 同时确认按 #137 与长期规则校正正文冲突:采购员默认可见 SYB 店铺只读页面且可由角色配置取消;AI 规格匹配才是采购员硬排除。

工单正文已同步校正,开始实施生产代码。

## 设计确认并开始实施 用户于 2026-08-28 明确确认 **#138 v1 原型通过**。 - 设计证据:https://git.ilapage.cn/attachments/0d1e252a-e463-4b28-8520-58e54b1d9b16 - 版本识别:图片右上角“待审核 · v1 · 2026-08-28” - 确认人:需求方用户 - 确认范围:角色菜单勾选结果、管理员完整菜单、采购员重新登录后的授权菜单、AI 菜单硬排除、未授权 URL、无 GoAuto 菜单权限。 - 同时确认按 #137 与长期规则校正正文冲突:采购员默认可见 SYB 店铺只读页面且可由角色配置取消;AI 规格匹配才是采购员硬排除。 工单正文已同步校正,开始实施生产代码。
Author
Owner

实现完成,待验收

已按确认的 v1 原型完成 #138,并推送提交 5feb4e8。

实现

  • 从 constantRoutes 移除 11 个 GoAuto 静态公共路由,登录后统一复用 GET /api/v1/menurole → generaMenu 生成业务路由和侧栏。
  • 后端返回空菜单时只保留工作台;未授权 GoAuto 深链接由动态兜底路由回退工作台。
  • 菜单接口非 200 或请求失败时拒绝路由生成,清除 Token 与旧动态路由并返回登录页,避免导航挂起或残留上一个角色的路由。
  • 正常退出、凭据重置和既有角色切换流程均执行 resetRouter(),保证角色菜单调整后重新登录生效。
  • 更新跨端契约测试,禁止 GoAuto 路由重新进入公共静态路由;#137 迁移测试继续逐项校验菜单 path、route name、component 和绑定。
  • 新增 Playwright 覆盖管理员全部菜单、采购员授权菜单/AI 硬隐藏、零 GoAuto 权限、菜单接口异常四类场景。

验证

  • go test ./app/goauto/access ./cmd/migrate/migration/version-local:通过。
  • pnpm exec eslint src/permission.js src/router/index.js src/store/modules/permission.js src/store/modules/user.js:通过。
  • pnpm run build:prod:通过。
  • pnpm exec playwright test tests/e2e/goauto-menu-permission.spec.ts --workers=1:4/4 通过。
  • .\scripts\verify.ps1 -Component all:服务端全量测试/构建、Web lint/构建、Android 单元测试/debug APK 全部通过;Web 仍有 30 个既有 warning,无 error。
  • 当前本地真实管理员会话中,直接访问 /purchase-tasks/index 已验证回退 /dashboard,证明静态入口已移除。

文档

  • 已先更新线上 Wiki Architecture-and-Code-Map 并在线回读 revision 40b34ee81f4207de6797b1a81ded6459b6dd776d。
  • 已执行一次 harness.py sync 和一次 sync --check,一致性检查通过。
  • 本工单未改变本地验证命令,因此 Local-Development-and-Verification 无长期文档影响。

尚待人工验收

当前本地数据库未返回 #137 的 GoAuto 菜单记录,说明该运行环境尚未应用/接入 #137 菜单迁移;本次没有擅自执行数据库迁移或修改真实角色权限。因此管理员/采购员真实账号菜单、角色勾选后重新登录、以及对应后端 Casbin 拒绝仍需在已应用 #137 迁移的环境验收。隔离浏览器测试已覆盖相同前端角色菜单契约。

工单保持打开并进入待验收。

## 实现完成,待验收 已按确认的 v1 原型完成 #138,并推送提交 `5feb4e8`。 ### 实现 - 从 `constantRoutes` 移除 11 个 GoAuto 静态公共路由,登录后统一复用 `GET /api/v1/menurole → generaMenu` 生成业务路由和侧栏。 - 后端返回空菜单时只保留工作台;未授权 GoAuto 深链接由动态兜底路由回退工作台。 - 菜单接口非 200 或请求失败时拒绝路由生成,清除 Token 与旧动态路由并返回登录页,避免导航挂起或残留上一个角色的路由。 - 正常退出、凭据重置和既有角色切换流程均执行 `resetRouter()`,保证角色菜单调整后重新登录生效。 - 更新跨端契约测试,禁止 GoAuto 路由重新进入公共静态路由;#137 迁移测试继续逐项校验菜单 path、route name、component 和绑定。 - 新增 Playwright 覆盖管理员全部菜单、采购员授权菜单/AI 硬隐藏、零 GoAuto 权限、菜单接口异常四类场景。 ### 验证 - `go test ./app/goauto/access ./cmd/migrate/migration/version-local`:通过。 - `pnpm exec eslint src/permission.js src/router/index.js src/store/modules/permission.js src/store/modules/user.js`:通过。 - `pnpm run build:prod`:通过。 - `pnpm exec playwright test tests/e2e/goauto-menu-permission.spec.ts --workers=1`:4/4 通过。 - `.\scripts\verify.ps1 -Component all`:服务端全量测试/构建、Web lint/构建、Android 单元测试/debug APK 全部通过;Web 仍有 30 个既有 warning,无 error。 - 当前本地真实管理员会话中,直接访问 `/purchase-tasks/index` 已验证回退 `/dashboard`,证明静态入口已移除。 ### 文档 - 已先更新线上 Wiki `Architecture-and-Code-Map` 并在线回读 revision `40b34ee81f4207de6797b1a81ded6459b6dd776d`。 - 已执行一次 `harness.py sync` 和一次 `sync --check`,一致性检查通过。 - 本工单未改变本地验证命令,因此 `Local-Development-and-Verification` 无长期文档影响。 ### 尚待人工验收 当前本地数据库未返回 #137 的 GoAuto 菜单记录,说明该运行环境尚未应用/接入 #137 菜单迁移;本次没有擅自执行数据库迁移或修改真实角色权限。因此管理员/采购员真实账号菜单、角色勾选后重新登录、以及对应后端 Casbin 拒绝仍需在已应用 #137 迁移的环境验收。隔离浏览器测试已覆盖相同前端角色菜单契约。 工单保持打开并进入待验收。
Author
Owner

验收通过

用户于 2026-08-28 明确确认「#138通过验收」。按提交 5feb4e8 与已回写验证证据完成验收,工单关闭。

本次仅记录验收结论;没有新的长期事实变化,不重复更新或同步 Wiki。

## 验收通过 用户于 2026-08-28 明确确认「#138通过验收」。按提交 `5feb4e8` 与已回写验证证据完成验收,工单关闭。 本次仅记录验收结论;没有新的长期事实变化,不重复更新或同步 Wiki。
ila closed this issue 2026-08-28 22:24:10 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#138