refactor: use patch api to refactor menu drag-and-drop sorting feature (#6462)

#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.19.x

#### What this PR does / why we need it:

使用 patch 接口重构菜单项拖动排序等功能。

#### Which issue(s) this PR fixes:

None

#### Special notes for your reviewer:

需要测试菜单项的拖动排序功能是否符合预期。

#### Does this PR introduce a user-facing change?

```release-note
使用 patch 接口重构菜单项拖动排序功能。
```
pull/6482/head
Ryan Wang 2024-08-16 22:42:33 +08:00 committed by GitHub
parent 10e3f57ca0
commit 7774eb1a3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 60 additions and 39 deletions

View File

@ -15,7 +15,6 @@ import {
} from "@halo-dev/components"; } from "@halo-dev/components";
import { useQuery, useQueryClient } from "@tanstack/vue-query"; import { useQuery, useQueryClient } from "@tanstack/vue-query";
import { useDebounceFn } from "@vueuse/core"; import { useDebounceFn } from "@vueuse/core";
import { cloneDeep } from "lodash-es";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import MenuItemEditingModal from "./components/MenuItemEditingModal.vue"; import MenuItemEditingModal from "./components/MenuItemEditingModal.vue";
@ -94,23 +93,26 @@ const onMenuItemEditingModalClose = () => {
}; };
const onMenuItemSaved = async (menuItem: MenuItem) => { const onMenuItemSaved = async (menuItem: MenuItem) => {
const menuToUpdate = cloneDeep(selectedMenu.value); if (!selectedMenu.value) {
return;
}
// update menu items // update menu items
if ( await coreApiClient.menu.patchMenu({
menuToUpdate && name: selectedMenu.value.metadata.name,
!menuToUpdate.spec.menuItems?.includes(menuItem.metadata.name) jsonPatchInner: [
) { {
menuToUpdate.spec.menuItems = [ op: "add",
...(menuToUpdate.spec.menuItems || []), path: "/spec/menuItems",
value: Array.from(
new Set([
...(selectedMenu.value.spec.menuItems || []),
menuItem.metadata.name, menuItem.metadata.name,
]; ])
),
await coreApiClient.menu.updateMenu({ },
name: menuToUpdate.metadata.name, ],
menu: menuToUpdate,
}); });
}
await queryClient.invalidateQueries({ queryKey: ["menus"] }); await queryClient.invalidateQueries({ queryKey: ["menus"] });
await refetch(); await refetch();
@ -124,9 +126,20 @@ const handleUpdateInBatch = useDebounceFn(async () => {
try { try {
batchUpdating.value = true; batchUpdating.value = true;
const promises = menuItemsToUpdate.map((menuItem) => const promises = menuItemsToUpdate.map((menuItem) =>
coreApiClient.menuItem.updateMenuItem({ coreApiClient.menuItem.patchMenuItem({
name: menuItem.metadata.name, name: menuItem.metadata.name,
menuItem, jsonPatchInner: [
{
op: "add",
path: "/spec/priority",
value: menuItem.spec.priority || 0,
},
{
op: "add",
path: "/spec/children",
value: menuItem.spec.children || [],
},
],
}) })
); );
await Promise.all(promises); await Promise.all(promises);
@ -165,16 +178,20 @@ const handleDelete = async (menuItem: MenuTreeItem) => {
await refetch(); await refetch();
// update items under menu // update items under menu
const menuToUpdate = cloneDeep(selectedMenu.value); await coreApiClient.menu.patchMenu({
if (menuToUpdate) { name: selectedMenu.value?.metadata.name as string,
menuToUpdate.spec.menuItems = menuToUpdate.spec.menuItems?.filter( jsonPatchInner: [
(name) => ![menuItem.metadata.name, ...childrenNames].includes(name) {
); op: "add",
await coreApiClient.menu.updateMenu({ path: "/spec/menuItems",
name: menuToUpdate.metadata.name, value:
menu: menuToUpdate, selectedMenu.value?.spec.menuItems?.filter(
(name) =>
![menuItem.metadata.name, ...childrenNames].includes(name)
) || [],
},
],
}); });
}
await queryClient.invalidateQueries({ queryKey: ["menus"] }); await queryClient.invalidateQueries({ queryKey: ["menus"] });

View File

@ -12,7 +12,7 @@ import { useI18n } from "vue-i18n";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
menu: Menu; menu: Menu;
parentMenuItem: MenuItem; parentMenuItem?: MenuItem;
menuItem?: MenuItem; menuItem?: MenuItem;
}>(), }>(),
{ {
@ -100,19 +100,23 @@ const handleSaveMenuItem = async () => {
// if parent menu item is selected, add the new menu item to the parent menu item // if parent menu item is selected, add the new menu item to the parent menu item
if (selectedParentMenuItem.value) { if (selectedParentMenuItem.value) {
const { data: menuItemToUpdate } = const { data: parentMenuItem } =
await coreApiClient.menuItem.getMenuItem({ await coreApiClient.menuItem.getMenuItem({
name: selectedParentMenuItem.value, name: selectedParentMenuItem.value,
}); });
menuItemToUpdate.spec.children = [ await coreApiClient.menuItem.patchMenuItem({
...(menuItemToUpdate.spec.children || []), name: selectedParentMenuItem.value,
jsonPatchInner: [
{
op: "add",
path: "/spec/children",
value: [
...(parentMenuItem.spec.children || []),
data.metadata.name, data.metadata.name,
]; ],
},
await coreApiClient.menuItem.updateMenuItem({ ],
name: menuItemToUpdate.metadata.name,
menuItem: menuItemToUpdate,
}); });
} }
@ -218,7 +222,7 @@ onMounted(() => {
} }
} }
selectedParentMenuItem.value = props.parentMenuItem?.metadata.name; selectedParentMenuItem.value = props.parentMenuItem?.metadata.name || "";
setFocus("displayNameInput"); setFocus("displayNameInput");
}); });