feat: add support for selecting parent menu item when creating menu item

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/3445/head
Ryan Wang 2022-10-11 15:33:51 +08:00
parent 2a12feccf1
commit 2ac0c525de
3 changed files with 98 additions and 14 deletions

View File

@ -28,8 +28,9 @@ import { useDebounceFn } from "@vueuse/core";
const menuItems = ref<MenuItem[]>([] as MenuItem[]);
const menuTreeItems = ref<MenuTreeItem[]>([] as MenuTreeItem[]);
const selectedMenu = ref<Menu | undefined>();
const selectedMenuItem = ref<MenuItem | null>(null);
const selectedMenu = ref<Menu>();
const selectedMenuItem = ref<MenuItem>();
const selectedParentMenuItem = ref<MenuItem>();
const loading = ref(false);
const menuListRef = ref();
const menuItemEditingModal = ref();
@ -66,6 +67,16 @@ const handleOpenEditingModal = (menuItem: MenuTreeItem) => {
menuItemEditingModal.value = true;
};
const handleOpenCreateByParentModal = (menuItem: MenuTreeItem) => {
selectedParentMenuItem.value = convertMenuTreeItemToMenuItem(menuItem);
menuItemEditingModal.value = true;
};
const onMenuItemEditingModalClose = () => {
selectedParentMenuItem.value = undefined;
selectedMenuItem.value = undefined;
};
const onMenuItemSaved = async (menuItem: MenuItem) => {
const menuToUpdate = cloneDeep(selectedMenu.value);
@ -143,7 +154,9 @@ const handleDelete = async (menuItem: MenuTreeItem) => {
<MenuItemEditingModal
v-model:visible="menuItemEditingModal"
:menu-item="selectedMenuItem"
@close="selectedMenuItem = null"
:parent-menu-item="selectedParentMenuItem"
:menu="selectedMenu"
@close="onMenuItemEditingModalClose"
@saved="onMenuItemSaved"
/>
<VPageHeader title="菜单">
@ -214,6 +227,7 @@ const handleDelete = async (menuItem: MenuTreeItem) => {
@change="handleUpdateInBatch"
@delete="handleDelete"
@open-editing="handleOpenEditingModal"
@open-create-by-parent="handleOpenCreateByParentModal"
/>
</VCard>
</div>

View File

@ -2,7 +2,7 @@
import { VButton, VModal, VSpace } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
import { computed, ref, watch } from "vue";
import type { MenuItem, Post, SinglePage } from "@halo-dev/api-client";
import type { Menu, MenuItem, Post, SinglePage } from "@halo-dev/api-client";
import { v4 as uuid } from "uuid";
import { apiClient } from "@/utils/api-client";
import { reset } from "@formkit/core";
@ -10,15 +10,20 @@ import cloneDeep from "lodash.clonedeep";
import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category";
import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag";
import { setFocus } from "@/formkit/utils/focus";
import type { FormKitOptionsProp } from "@formkit/inputs";
const props = withDefaults(
defineProps<{
visible: boolean;
menuItem: MenuItem | null;
menu?: Menu;
parentMenuItem: MenuItem;
menuItem?: MenuItem;
}>(),
{
visible: false,
menuItem: null,
menu: undefined,
parentMenuItem: undefined,
menuItem: undefined,
}
);
@ -42,6 +47,8 @@ const initialFormState: MenuItem = {
},
};
const menuItemMap = ref<FormKitOptionsProp>();
const selectedParentMenuItem = ref<string>("");
const formState = ref<MenuItem>(cloneDeep(initialFormState));
const saving = ref(false);
@ -49,6 +56,25 @@ const isUpdateMode = computed(() => {
return !!formState.value.metadata.creationTimestamp;
});
const handleFetchMenuItems = async () => {
try {
const { data } = await apiClient.extension.menuItem.listv1alpha1MenuItem({
fieldSelector: [`name=(${props.menu?.spec.menuItems?.join(",")})`],
});
menuItemMap.value = [
{ label: "无", value: undefined },
...data.items.map((menuItem) => {
return {
label: menuItem.status?.displayName as string,
value: menuItem.metadata.name,
};
}),
];
} catch (error) {
console.log("Failed to fetch menu items", error);
}
};
const handleSaveMenuItem = async () => {
try {
saving.value = true;
@ -81,6 +107,25 @@ const handleSaveMenuItem = async () => {
await apiClient.extension.menuItem.createv1alpha1MenuItem({
menuItem: formState.value,
});
// if parent menu item is selected, add the new menu item to the parent menu item
if (selectedParentMenuItem.value) {
const { data: menuItemToUpdate } =
await apiClient.extension.menuItem.getv1alpha1MenuItem({
name: selectedParentMenuItem.value,
});
menuItemToUpdate.spec.children = [
...(menuItemToUpdate.spec.children || []),
data.metadata.name,
];
await apiClient.extension.menuItem.updatev1alpha1MenuItem({
name: menuItemToUpdate.metadata.name,
menuItem: menuItemToUpdate,
});
}
onVisibleChange(false);
emit("saved", data);
}
@ -103,6 +148,7 @@ const handleResetForm = () => {
formState.value.metadata.name = uuid();
selectedMenuItemSource.value = menuItemSources[0].value;
selectedRef.value = "";
selectedParentMenuItem.value = "";
reset("menuitem-form");
};
@ -110,6 +156,7 @@ watch(
() => props.visible,
(visible) => {
if (visible) {
selectedParentMenuItem.value = props.parentMenuItem?.metadata.name;
setFocus("displayNameInput");
if (!props.menuItem) {
@ -287,6 +334,7 @@ watch(
() => props.visible,
(newValue) => {
if (newValue) {
handleFetchMenuItems();
handleFetchCategories();
handleFetchTags();
handleFetchPosts();
@ -310,6 +358,14 @@ watch(
:config="{ validationVisibility: 'submit' }"
@submit="handleSaveMenuItem"
>
<FormKit
v-if="!isUpdateMode && menuItemMap"
v-model="selectedParentMenuItem"
label="上级菜单项"
type="select"
:options="menuItemMap"
/>
<FormKit
v-model="selectedMenuItemSource"
:options="menuItemSources"
@ -317,8 +373,7 @@ watch(
label="类型"
type="select"
@change="onMenuItemSourceChange"
>
</FormKit>
/>
<FormKit
v-if="selectedMenuItemSource === 'custom'"
@ -328,7 +383,8 @@ watch(
type="text"
name="displayName"
validation="required"
></FormKit>
/>
<FormKit
v-if="selectedMenuItemSource === 'custom'"
v-model="formState.spec.href"
@ -336,7 +392,7 @@ watch(
type="text"
name="href"
validation="required"
></FormKit>
/>
<FormKit
v-if="selectedMenuItemSource === 'post'"
@ -345,7 +401,7 @@ watch(
type="select"
:options="postMap"
validation="required"
></FormKit>
/>
<FormKit
v-if="selectedMenuItemSource === 'singlePage'"
@ -354,7 +410,7 @@ watch(
type="select"
:options="singlePageMap"
validation="required"
></FormKit>
/>
<FormKit
v-if="selectedMenuItemSource === 'tag'"
@ -363,7 +419,7 @@ watch(
type="select"
:options="tagMap"
validation="required"
></FormKit>
/>
<FormKit
v-if="selectedMenuItemSource === 'category'"
@ -372,7 +428,7 @@ watch(
type="select"
:options="categoryMap"
validation="required"
></FormKit>
/>
</FormKit>
<template #footer>
<VSpace>

View File

@ -26,6 +26,7 @@ withDefaults(
const emit = defineEmits<{
(event: "change"): void;
(event: "open-editing", menuItem: MenuTreeItem): void;
(event: "open-create-by-parent", menuItem: MenuTreeItem): void;
(event: "delete", menuItem: MenuTreeItem): void;
}>();
@ -39,6 +40,10 @@ function onOpenEditingModal(menuItem: MenuTreeItem) {
emit("open-editing", menuItem);
}
function onOpenCreateByParentModal(menuItem: MenuTreeItem) {
emit("open-create-by-parent", menuItem);
}
function onDelete(menuItem: MenuTreeItem) {
emit("delete", menuItem);
}
@ -114,6 +119,14 @@ function getMenuItemRefDisplayName(menuItem: MenuTreeItem) {
>
修改
</VButton>
<VButton
v-close-popper
block
type="default"
@click="onOpenCreateByParentModal(menuItem)"
>
添加子菜单项
</VButton>
<VButton
v-close-popper
block
@ -130,6 +143,7 @@ function getMenuItemRefDisplayName(menuItem: MenuTreeItem) {
@change="onChange"
@delete="onDelete"
@open-editing="onOpenEditingModal"
@open-create-by-parent="onOpenCreateByParentModal"
/>
</li>
</template>