[fix]:[FL-155][菜单管理页面最后3项细节优化]
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -128,3 +128,21 @@
|
||||
- 风险与关注点:
|
||||
- `/api/v1/system-messages/me` 新增可选 `message_type` 参数,未传参时保持原列表语义;前端不再做本地类型过滤,分页 total 与服务端过滤结果一致。
|
||||
- 改动影响系统消息列表展示与筛选,不改变创建、删除、标记已读接口字段。
|
||||
|
||||
# Work Log - 菜单管理页面最终细节对齐(FL-155)
|
||||
|
||||
- 背景:
|
||||
- 菜单管理页需要补齐启用/禁用 mutation 组织、移动卡片字段列宽和加载完成提示条件三处细节,与用户管理页保持一致。
|
||||
|
||||
- 本次处理:
|
||||
- 菜单启用/禁用移除独立 `updateMenuStatusMutation`,改为复用 `updateMenuMutation` 通过 `PATCH /api/v1/admin/menus/{menuId}` 提交 `{ status }`。
|
||||
- `.admin-menus-menu-card-field` 标签列宽从 `72px` 调整为 `64px`。
|
||||
- 移动卡片“已加载全部”提示条件简化为 `allLoadedMenus.length >= menuTotal && allLoadedMenus.length > 0`。
|
||||
|
||||
- 验证:
|
||||
- 基线:`npm --workspace web exec tsc --noEmit` 通过。
|
||||
- 修改后:`npm --workspace web exec eslint src/app/admin/menus/page.tsx --max-warnings=0` 通过。
|
||||
- 修改后:`npm --workspace web exec tsc --noEmit` 通过。
|
||||
|
||||
- 风险与关注点:
|
||||
- 改动仅影响菜单管理页前端数据 mutation 组织和移动端展示条件,不改变接口路径、请求/响应字段或权限语义。
|
||||
|
||||
@@ -351,7 +351,7 @@ export default function AdminMenusPage() {
|
||||
});
|
||||
|
||||
const updateMenuMutation = useMutation({
|
||||
mutationFn: async ({ menuId, payload }: { menuId: string; payload: MenuMutationPayload }) => {
|
||||
mutationFn: async ({ menuId, payload }: { menuId: string; payload: Partial<MenuMutationPayload> }) => {
|
||||
const response = await fetchWithAuth(`/api/v1/admin/menus/${menuId}`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -360,18 +360,33 @@ export default function AdminMenusPage() {
|
||||
if (!response.ok) throw new Error(await readApiError(response));
|
||||
return response.json() as Promise<MenuItem>;
|
||||
},
|
||||
onMutate: () => {
|
||||
onMutate: ({ menuId, payload }) => {
|
||||
if (payload.status && Object.keys(payload).length === 1) {
|
||||
setUpdatingStatusMenuId(menuId);
|
||||
}
|
||||
setError("");
|
||||
setSuccess("");
|
||||
},
|
||||
onSuccess: async () => {
|
||||
setSuccess("菜单已更新");
|
||||
closeDialog();
|
||||
onSuccess: async (_, variables) => {
|
||||
if (variables.payload.status && Object.keys(variables.payload).length === 1) {
|
||||
setSuccess(variables.payload.status === "enabled" ? "菜单已启用" : "菜单已禁用");
|
||||
} else {
|
||||
setSuccess("菜单已更新");
|
||||
closeDialog();
|
||||
}
|
||||
await refreshData();
|
||||
},
|
||||
onError: (candidate) => {
|
||||
onError: (candidate, variables) => {
|
||||
setSuccess("");
|
||||
setError(candidate instanceof Error ? candidate.message : "更新菜单失败");
|
||||
const fallbackMessage = variables.payload.status && Object.keys(variables.payload).length === 1
|
||||
? "菜单状态更新失败"
|
||||
: "更新菜单失败";
|
||||
setError(candidate instanceof Error ? candidate.message : fallbackMessage);
|
||||
},
|
||||
onSettled: (_data, _error, variables) => {
|
||||
if (variables?.payload.status && Object.keys(variables.payload).length === 1) {
|
||||
setUpdatingStatusMenuId(null);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -403,32 +418,6 @@ export default function AdminMenusPage() {
|
||||
onSettled: () => setDeletingMenuId(null),
|
||||
});
|
||||
|
||||
const updateMenuStatusMutation = useMutation({
|
||||
mutationFn: async ({ menuId, status }: { menuId: string; status: "enabled" | "disabled" }) => {
|
||||
const response = await fetchWithAuth(`/api/v1/admin/menus/${menuId}`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ status }),
|
||||
});
|
||||
if (!response.ok) throw new Error(await readApiError(response));
|
||||
return response.json() as Promise<MenuItem>;
|
||||
},
|
||||
onMutate: ({ menuId }) => {
|
||||
setUpdatingStatusMenuId(menuId);
|
||||
setError("");
|
||||
setSuccess("");
|
||||
},
|
||||
onSuccess: async (_, variables) => {
|
||||
setSuccess(variables.status === "enabled" ? "菜单已启用" : "菜单已禁用");
|
||||
await refreshData();
|
||||
},
|
||||
onError: (candidate) => {
|
||||
setSuccess("");
|
||||
setError(candidate instanceof Error ? candidate.message : "菜单状态更新失败");
|
||||
},
|
||||
onSettled: () => setUpdatingStatusMenuId(null),
|
||||
});
|
||||
|
||||
const submit = useCallback(async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
@@ -479,8 +468,8 @@ export default function AdminMenusPage() {
|
||||
|
||||
const updateMenuStatus = useCallback(async (menu: MenuItem) => {
|
||||
const nextStatus: "enabled" | "disabled" = menu.status === "enabled" ? "disabled" : "enabled";
|
||||
updateMenuStatusMutation.mutate({ menuId: menu.id, status: nextStatus });
|
||||
}, [updateMenuStatusMutation]);
|
||||
updateMenuMutation.mutate({ menuId: menu.id, payload: { status: nextStatus } });
|
||||
}, [updateMenuMutation]);
|
||||
|
||||
const columns = useMemo<TableColumnsType<MenuItem>>(() => {
|
||||
const base: TableColumnsType<MenuItem> = [
|
||||
@@ -876,7 +865,7 @@ export default function AdminMenusPage() {
|
||||
<Spin tip="加载更多..." />
|
||||
</div>
|
||||
)}
|
||||
{!menusQuery.isLoading && !isLoadingMore && allLoadedMenus.length >= menuTotal && allLoadedMenus.length > 0 && (
|
||||
{allLoadedMenus.length >= menuTotal && allLoadedMenus.length > 0 && (
|
||||
<div style={{ textAlign: "center", padding: "20px 0" }}>
|
||||
<Typography.Text type="secondary">
|
||||
已加载全部 {allLoadedMenus.length} 条数据
|
||||
|
||||
@@ -554,7 +554,7 @@ body {
|
||||
|
||||
.admin-menus-menu-card-field {
|
||||
display: grid;
|
||||
grid-template-columns: 72px minmax(0, 1fr);
|
||||
grid-template-columns: 64px minmax(0, 1fr);
|
||||
gap: 8px;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user