diff --git a/memory/2026-06-20.md b/memory/2026-06-20.md new file mode 100644 index 0000000..762d3a0 --- /dev/null +++ b/memory/2026-06-20.md @@ -0,0 +1,19 @@ +# Work Log - 菜单管理页面一致性优化(FL-151) + +- 背景: + - 菜单管理页需要继续对齐用户管理页的消息反馈、筛选表单、空态与表格滚动配置规范。 + +- 本次处理: + - 移除菜单管理页对 `App.useApp()` 的依赖,创建、编辑、删除结果统一走 `error` / `success` state + `useToastFeedback`。 + - 桌面筛选表单项由 Tailwind `min-w-*` 改为与用户管理页一致的 `style={{ width: ... }}`。 + - 表格空态 `Empty` 属性顺序调整为 `image` 在前、`description` 在后。 + - 移除菜单表格 `scroll.x`,仅保留纵向滚动配置,与用户管理页保持一致。 + +- 验证: + - 基线:`npm --workspace web exec eslint src/app/admin/menus/page.tsx` 通过。 + - 基线:`npm --workspace web exec tsc --noEmit` 通过。 + - 修改后:`npm --workspace web exec eslint src/app/admin/menus/page.tsx` 通过。 + - 修改后:`npm --workspace web exec tsc --noEmit` 通过。 + +- 风险与关注点: + - 改动仅影响菜单管理页前端展示与提示机制,不改变菜单接口、字段结构或权限语义。 diff --git a/web/src/app/admin/menus/page.tsx b/web/src/app/admin/menus/page.tsx index 3841c43..f73bf3a 100644 --- a/web/src/app/admin/menus/page.tsx +++ b/web/src/app/admin/menus/page.tsx @@ -3,7 +3,6 @@ import Link from "next/link"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { - App, Button, Card, Checkbox, @@ -91,7 +90,6 @@ function normalizeMenuItemPath(menu: MenuItem): MenuItem { export default function AdminMenusPage() { const { user, initializing, fetchWithAuth, hasPermission } = useAuth(); - const { message: messageApi, modal } = App.useApp(); const isMobile = useMobileDetection(); const [menus, setMenus] = useState([]); const [menuTotal, setMenuTotal] = useState(0); @@ -321,6 +319,7 @@ export default function AdminMenusPage() { try { setSaving(true); setError(""); + setSuccess(""); const values = await form.validateFields(); const payload = { @@ -352,11 +351,10 @@ export default function AdminMenusPage() { if (!response.ok) { const msg = await readApiError(response); setError(msg); - messageApi.error(msg); return; } - messageApi.success(editingMenuId ? "菜单已更新" : "菜单已创建"); + setSuccess(editingMenuId ? "菜单已更新" : "菜单已创建"); closeDialog(); await loadMenus(paginationCurrent, paginationPageSize); } catch (candidate) { @@ -372,11 +370,10 @@ export default function AdminMenusPage() { const msg = candidate instanceof Error ? candidate.message : "提交失败,请稍后重试"; setError(msg); - messageApi.error(msg); } finally { setSaving(false); } - }, [closeDialog, editingMenuId, fetchWithAuth, form, loadMenus, messageApi, paginationCurrent, paginationPageSize]); + }, [closeDialog, editingMenuId, fetchWithAuth, form, loadMenus, paginationCurrent, paginationPageSize]); const removeMenu = useCallback(async (menu: MenuItem) => { setDeletingMenuId(menu.id); @@ -390,31 +387,32 @@ export default function AdminMenusPage() { if (!response.ok) { const msg = await readApiError(response); setError(msg); - messageApi.error(msg); return; } - messageApi.success("菜单已删除"); + setSuccess("菜单已删除"); if (editingMenuId === menu.id) { closeDialog(); } setMenuTotal((previous) => Math.max(0, previous - 1)); setAllLoadedMenus((previous) => previous.filter((item) => item.id !== menu.id)); await loadMenus(paginationCurrent, paginationPageSize); + } catch (candidate) { + setError(candidate instanceof Error ? candidate.message : "菜单删除失败"); } finally { setDeletingMenuId(null); } - }, [closeDialog, editingMenuId, fetchWithAuth, loadMenus, messageApi, paginationCurrent, paginationPageSize]); + }, [closeDialog, editingMenuId, fetchWithAuth, loadMenus, paginationCurrent, paginationPageSize]); const confirmRemoveMenu = useCallback((menu: MenuItem) => { - modal.confirm({ + Modal.confirm({ title: `确认删除菜单 ${menu.name}(${menu.code})?`, okText: "删除", cancelText: "取消", okButtonProps: { danger: true }, onOk: () => removeMenu(menu), }); - }, [modal, removeMenu]); + }, [removeMenu]); const updateMenuStatus = useCallback(async (menu: MenuItem) => { const nextStatus: "enabled" | "disabled" = menu.status === "enabled" ? "disabled" : "enabled"; @@ -748,7 +746,7 @@ export default function AdminMenusPage() { ) : (
- + - + > value={statusFilter === "all" ? undefined : statusFilter} allowClear @@ -784,7 +782,7 @@ export default function AdminMenusPage() { columns={columns} loading={loading} tableLayout="fixed" - scroll={{ x: 1200, y: tableScrollY }} + scroll={{ y: tableScrollY }} pagination={{ current: pagination.current, pageSize: pagination.pageSize, @@ -799,7 +797,12 @@ export default function AdminMenusPage() { }, }} locale={{ - emptyText: , + emptyText: ( + + ), }} />