diff --git a/MEMORY.md b/MEMORY.md index 85e62b8..598fe43 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -1018,3 +1018,9 @@ - 总数以接口返回 `total` 为准。 - 筛选条件(关键词/塔型/风险等级)或线路切换时,分页需自动回到第 1 页,避免落在无数据页。 - 地图视图保留大页查询(当前 500 条)用于展示线路点位,不与表格分页参数共用同一页码。 + +## 角色/菜单配置口径(2026-05-01) + +- 角色管理页面(`/admin/roles`)当前仅提供角色基础信息与“可见菜单”配置,不再提供权限点(`permission_codes`)配置入口。 +- 菜单管理页面(`/admin/menus`)当前不再提供菜单权限码(`permission_code`)配置入口与列表展示。 +- 后端权限字段与接口兼容能力保留,作为历史数据与鉴权映射兜底;前端交互层默认不暴露该配置。 diff --git a/memory/2026-05-01.md b/memory/2026-05-01.md index 0e7b137..e0241e1 100644 --- a/memory/2026-05-01.md +++ b/memory/2026-05-01.md @@ -419,3 +419,34 @@ - 风险与影响: - `.img/.tif` 回填依赖 `rasterio`(及底层 GDAL 运行时),部署环境需确保镜像能成功安装该依赖。 - 栅格 bbox 直接来自源栅格 CRS;非经纬度坐标系场景会返回告警,便于识别与后续治理。 + +## Work Log - 去掉角色权限点与菜单权限码配置(2026-05-01) + +- 背景: + - Issue `FL-139` 要求“去掉角色管理的权限点配置,菜单的权限码配置”。 + +- 本次改动(最小闭环): + - 角色管理页面:`web/src/app/admin/roles/page.tsx` + - 移除权限点配置入口与相关请求链路: + - 移除 `permissions` 状态与 `/api/v1/admin/permissions` 加载请求。 + - 新建/编辑角色表单移除 `permission_codes` 字段,仅保留 `code/name/menu_ids`。 + - 角色更新请求不再提交 `permission_codes`。 + - 列表展示移除“权限”列,仅展示“角色编码/角色名称/菜单/操作”。 + - 搜索口径同步调整为“角色编码、名称、菜单”。 + - 菜单管理页面:`web/src/app/admin/menus/page.tsx` + - 移除菜单权限码配置入口: + - 菜单表单移除 `permission_code` 字段。 + - 新建/编辑菜单提交 payload 不再包含 `permission_code`。 + - 列表展示移除“权限码”列。 + - 搜索口径移除权限码匹配,关键词仅匹配“编码/名称/路径”。 + - 后台首页文案:`web/src/app/admin/page.tsx` + - 角色管理说明改为“配置角色并分配菜单可见范围”。 + - 菜单管理说明改为“维护后台导航结构、菜单层级与展示状态”。 + +- 验证(遵循任务约束,未执行编译检查): + - `git diff` 已确认改动仅涉及上述三个前端文件。 + - 代码扫描确认上述页面不再包含 `permission_codes` / `permission_code` 配置与展示逻辑。 + +- 风险与影响: + - 影响范围限定在前端管理页交互层;后端接口仍保持兼容,可继续返回权限相关字段但前端不再暴露配置入口。 + - 若后续需彻底下线该能力(含后端字段/持久化),需单独评估接口契约与历史数据兼容。 diff --git a/web/src/app/admin/menus/page.tsx b/web/src/app/admin/menus/page.tsx index 360e52a..98b8ba3 100644 --- a/web/src/app/admin/menus/page.tsx +++ b/web/src/app/admin/menus/page.tsx @@ -48,7 +48,6 @@ type MenuFormValues = { visible: boolean; cacheable: boolean; component?: string; - permission_code?: string; }; const SORT_OPTIONS: Array<{ value: SortKey; label: string }> = [ @@ -108,7 +107,6 @@ const DEFAULT_FORM_VALUES: MenuFormValues = { visible: true, cacheable: false, component: "", - permission_code: "", }; function compareMenuIds(a: string, b: string): number { @@ -166,7 +164,7 @@ export default function AdminMenusPage() { if (!query) { return true; } - const haystack = [menu.code, menu.name, menu.path ?? "", menu.permission_code ?? ""] + const haystack = [menu.code, menu.name, menu.path ?? ""] .join(" ") .toLowerCase(); return haystack.includes(query); @@ -250,7 +248,6 @@ export default function AdminMenusPage() { visible: menu.visible, cacheable: menu.cacheable, component: menu.component ?? "", - permission_code: menu.permission_code ?? "", }); setDialogOpen(true); }, [form]); @@ -273,7 +270,6 @@ export default function AdminMenusPage() { visible: values.visible, cacheable: values.cacheable, component: values.component?.trim() ? values.component.trim() : null, - permission_code: values.permission_code?.trim() ? values.permission_code.trim() : null, }; const response = editingMenuId @@ -362,12 +358,6 @@ export default function AdminMenusPage() { width: 220, render: (value: string | null) => value || "-", }, - { - title: "权限码", - dataIndex: "permission_code", - width: 180, - render: (value: string | null) => value || "-", - }, { title: "父菜单", dataIndex: "parent_id", @@ -488,7 +478,7 @@ export default function AdminMenusPage() { allowClear value={keyword} onChange={(event) => setKeyword(event.currentTarget.value)} - placeholder="按编码/名称/路径/权限筛选" + placeholder="按编码/名称/路径筛选" /> @@ -634,12 +624,6 @@ export default function AdminMenusPage() { - - - - - - 可见 diff --git a/web/src/app/admin/page.tsx b/web/src/app/admin/page.tsx index 7c28911..b452c23 100644 --- a/web/src/app/admin/page.tsx +++ b/web/src/app/admin/page.tsx @@ -43,7 +43,7 @@ const CARDS: DashboardCard[] = [ { href: "/roles", title: "角色管理", - description: "配置角色、绑定权限点、分配菜单可见范围。", + description: "配置角色并分配菜单可见范围。", category: "权限", icon: , visible: (hasPermission) => hasPermission("role.read") || hasPermission("role.manage"), @@ -51,7 +51,7 @@ const CARDS: DashboardCard[] = [ { href: "/menus", title: "菜单管理", - description: "维护后台导航、菜单层级和菜单对应权限。", + description: "维护后台导航结构、菜单层级与展示状态。", category: "权限", icon: , visible: (hasPermission) => hasPermission("menu.read") || hasPermission("menu.manage"), diff --git a/web/src/app/admin/roles/page.tsx b/web/src/app/admin/roles/page.tsx index fbdf301..a3c7860 100644 --- a/web/src/app/admin/roles/page.tsx +++ b/web/src/app/admin/roles/page.tsx @@ -27,25 +27,22 @@ import type { ComponentType } from "react"; import { useAuth } from "@/components/auth-provider"; import { useTopicSubscription } from "@/hooks/use-topic-subscription"; import { readApiError } from "@/lib/api"; -import type { MenuItem, PermissionItem, RoleItem, RoleListResponse } from "@/types/auth"; +import type { MenuItem, RoleItem, RoleListResponse } from "@/types/auth"; const AntCard = Card as unknown as ComponentType; const AntResult = Result as unknown as ComponentType; -type PermissionResponse = { items: PermissionItem[] }; type MenuListResponse = { items: MenuItem[]; total: number }; type RoleFormValues = { code: string; name: string; - permission_codes: string[]; menu_ids: string[]; }; const EMPTY_FORM: RoleFormValues = { code: "", name: "", - permission_codes: [], menu_ids: [], }; @@ -55,7 +52,6 @@ export default function AdminRolesPage() { const [form] = Form.useForm(); const [roles, setRoles] = useState([]); const [searchKeyword, setSearchKeyword] = useState(""); - const [permissions, setPermissions] = useState([]); const [menus, setMenus] = useState([]); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); @@ -66,15 +62,6 @@ export default function AdminRolesPage() { const canRead = hasPermission("role.read") || hasPermission("role.manage"); const canManage = hasPermission("role.manage"); - const permissionOptions = useMemo( - () => - permissions.map((permission) => ({ - value: permission.code, - label: `${permission.name || permission.code} (${permission.code})`, - })), - [permissions], - ); - const menuOptions = useMemo( () => menus.map((menu) => ({ value: menu.id, label: `${menu.name} (${menu.code})` })), [menus], @@ -97,7 +84,6 @@ export default function AdminRolesPage() { const haystack = [ role.code, role.name, - role.permission_codes.join(" "), menuNames, ] .join(" ") @@ -115,28 +101,22 @@ export default function AdminRolesPage() { setLoading(true); setError(""); try { - const [roleRes, permissionRes, menuRes] = await Promise.all([ + const [roleRes, menuRes] = await Promise.all([ fetchWithAuth("/api/v1/admin/roles"), - fetchWithAuth("/api/v1/admin/permissions"), fetchWithAuth("/api/v1/admin/menus"), ]); if (!roleRes.ok) { throw new Error(await readApiError(roleRes)); } - if (!permissionRes.ok) { - throw new Error(await readApiError(permissionRes)); - } if (!menuRes.ok) { throw new Error(await readApiError(menuRes)); } const rolePayload = (await roleRes.json()) as RoleListResponse; - const permissionPayload = (await permissionRes.json()) as PermissionResponse; const menuPayload = (await menuRes.json()) as MenuListResponse; setRoles(rolePayload.items); - setPermissions(permissionPayload.items); setMenus(menuPayload.items); } catch (candidate) { setError(candidate instanceof Error ? candidate.message : "角色数据加载失败"); @@ -183,7 +163,6 @@ export default function AdminRolesPage() { form.setFieldsValue({ code: role.code, name: role.name, - permission_codes: role.permission_codes, menu_ids: role.menu_ids, }); setDialogOpen(true); @@ -198,7 +177,6 @@ export default function AdminRolesPage() { const payload: RoleFormValues = { code: values.code.trim(), name: values.name.trim(), - permission_codes: values.permission_codes ?? [], menu_ids: values.menu_ids ?? [], }; @@ -208,7 +186,6 @@ export default function AdminRolesPage() { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: payload.name, - permission_codes: payload.permission_codes, menu_ids: payload.menu_ids, }), }) @@ -282,22 +259,6 @@ export default function AdminRolesPage() { dataIndex: "name", width: 180, }, - { - title: "权限", - dataIndex: "permission_codes", - render: (value: string[]) => { - if (value.length === 0) { - return 未绑定权限; - } - return ( - - {value.map((permissionCode) => ( - {permissionCode} - ))} - - ); - }, - }, { title: "菜单", dataIndex: "menu_ids", @@ -414,7 +375,7 @@ export default function AdminRolesPage() { setSearchKeyword(event.currentTarget.value)} @@ -482,16 +443,6 @@ export default function AdminRolesPage() { - -