From 2fd9cbde3385a594ecedeb4ac22e131379b0f132 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Mon, 19 Jun 2023 10:54:11 +0800 Subject: [PATCH] feat: add support for selecting the parent category when creating a new category (#4056) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /area console /kind feature /milestone 2.7.x #### What this PR does / why we need it: 支持在创建分类的时候选择上级分类。 image #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/4040 #### Special notes for your reviewer: 测试方式: 1. 测试新建的时候指定上级分类的功能是否正常。 2. 点击某个分类的操作按钮,选择添加子分类的菜单项,检查在新建分类的表单中上级分类是否选中了此分类。 #### Does this PR introduce a user-facing change? ```release-note Console 端的文章分类支持在新建时指定上级分类。 ``` --- console/src/locales/en.yaml | 4 + console/src/locales/zh-CN.yaml | 4 + console/src/locales/zh-TW.yaml | 4 + .../posts/categories/CategoryList.vue | 13 +++- .../components/CategoryEditingModal.vue | 77 +++++++++++++++---- .../components/CategoryListItem.vue | 9 +++ 6 files changed, 93 insertions(+), 18 deletions(-) diff --git a/console/src/locales/en.yaml b/console/src/locales/en.yaml index 30db58328..273887722 100644 --- a/console/src/locales/en.yaml +++ b/console/src/locales/en.yaml @@ -276,6 +276,8 @@ core: delete: title: Are you sure you want to delete this category? description: After deleting this category, the association with corresponding articles will be removed. This operation cannot be undone. + add_sub_category: + button: Add sub category editing_modal: titles: update: Update post category @@ -284,6 +286,8 @@ core: general: General annotations: Annotations fields: + parent: + label: Parent display_name: label: Display name slug: diff --git a/console/src/locales/zh-CN.yaml b/console/src/locales/zh-CN.yaml index 1d31a7a1b..33fa5d3ce 100644 --- a/console/src/locales/zh-CN.yaml +++ b/console/src/locales/zh-CN.yaml @@ -276,6 +276,8 @@ core: delete: title: 确定要删除该分类吗? description: 删除此分类之后,对应文章的关联将被解除。该操作不可恢复。 + add_sub_category: + button: 新增子分类 editing_modal: titles: update: 编辑文章分类 @@ -284,6 +286,8 @@ core: general: 常规 annotations: 元数据 fields: + parent: + label: 上级分类 display_name: label: 名称 slug: diff --git a/console/src/locales/zh-TW.yaml b/console/src/locales/zh-TW.yaml index 117394df0..9e3d2166b 100644 --- a/console/src/locales/zh-TW.yaml +++ b/console/src/locales/zh-TW.yaml @@ -276,6 +276,8 @@ core: delete: title: 確定要刪除該分類嗎? description: 刪除此分類之後,對應文章的關聯將被解除。該操作不可恢復。 + add_sub_category: + button: 新增子分類 editing_modal: titles: update: 編輯文章分類 @@ -284,6 +286,8 @@ core: general: 常規 annotations: 元數據 fields: + parent: + label: 上級分類 display_name: label: 名稱 slug: diff --git a/console/src/modules/contents/posts/categories/CategoryList.vue b/console/src/modules/contents/posts/categories/CategoryList.vue index e7927fccf..186b23f60 100644 --- a/console/src/modules/contents/posts/categories/CategoryList.vue +++ b/console/src/modules/contents/posts/categories/CategoryList.vue @@ -33,7 +33,8 @@ import { useDebounceFn } from "@vueuse/core"; import { usePostCategory } from "./composables/use-post-category"; const editingModal = ref(false); -const selectedCategory = ref(null); +const selectedCategory = ref(); +const selectedParentCategory = ref(); const { categories, @@ -68,8 +69,14 @@ const handleOpenEditingModal = (category: CategoryTree) => { editingModal.value = true; }; +const handleOpenCreateByParentModal = (category: CategoryTree) => { + selectedParentCategory.value = convertCategoryTreeToCategory(category); + editingModal.value = true; +}; + const onEditingModalClose = () => { - selectedCategory.value = null; + selectedCategory.value = undefined; + selectedParentCategory.value = undefined; handleFetchCategories(); }; @@ -77,6 +84,7 @@ const onEditingModalClose = () => { @@ -147,6 +155,7 @@ const onEditingModalClose = () => { @change="handleUpdateInBatch" @delete="handleDelete" @open-editing="handleOpenEditingModal" + @open-create-by-parent="handleOpenCreateByParentModal" /> diff --git a/console/src/modules/contents/posts/categories/components/CategoryEditingModal.vue b/console/src/modules/contents/posts/categories/components/CategoryEditingModal.vue index 87e5acda9..6aab1654c 100644 --- a/console/src/modules/contents/posts/categories/components/CategoryEditingModal.vue +++ b/console/src/modules/contents/posts/categories/components/CategoryEditingModal.vue @@ -28,11 +28,13 @@ import { useI18n } from "vue-i18n"; const props = withDefaults( defineProps<{ visible: boolean; - category: Category | null; + category?: Category; + parentCategory?: Category; }>(), { visible: false, - category: null, + category: undefined, + parentCategory: undefined, } ); @@ -63,6 +65,7 @@ const initialFormState: Category = { }; const formState = ref(cloneDeep(initialFormState)); +const selectedParentCategory = ref(""); const saving = ref(false); const isUpdateMode = computed(() => { @@ -100,9 +103,45 @@ const handleSaveCategory = async () => { category: formState.value, }); } else { - await apiClient.extension.category.createcontentHaloRunV1alpha1Category({ - category: formState.value, - }); + // Gets parent category, calculates priority and updates it. + let parentCategory: Category | undefined = undefined; + + if (selectedParentCategory.value) { + const { data } = + await apiClient.extension.category.getcontentHaloRunV1alpha1Category({ + name: selectedParentCategory.value, + }); + parentCategory = data; + } + + const priority = parentCategory?.spec.children + ? parentCategory.spec.children.length + 1 + : 0; + + formState.value.spec.priority = priority; + + const { data: createdCategory } = + await apiClient.extension.category.createcontentHaloRunV1alpha1Category( + { + category: formState.value, + } + ); + + if (parentCategory) { + parentCategory.spec.children = Array.from( + new Set([ + ...(parentCategory.spec.children || []), + createdCategory.metadata.name, + ]) + ); + + await apiClient.extension.category.updatecontentHaloRunV1alpha1Category( + { + name: selectedParentCategory.value, + category: parentCategory, + } + ); + } } onVisibleChange(false); @@ -122,6 +161,7 @@ const onVisibleChange = (visible: boolean) => { }; const handleResetForm = () => { + selectedParentCategory.value = ""; formState.value = cloneDeep(initialFormState); reset("category-form"); }; @@ -130,18 +170,15 @@ watch( () => props.visible, (visible) => { if (visible) { - setFocus("displayNameInput"); - } else { - handleResetForm(); - } - } -); + if (props.parentCategory) { + selectedParentCategory.value = props.parentCategory.metadata.name; + } -watch( - () => props.category, - (category) => { - if (category) { - formState.value = cloneDeep(category); + if (props.category) { + formState.value = cloneDeep(props.category); + } + + setFocus("displayNameInput"); } else { handleResetForm(); } @@ -189,6 +226,14 @@ const { handleGenerateSlug } = useSlugify(
+ (); @@ -39,6 +40,10 @@ function onOpenEditingModal(category: CategoryTree) { emit("open-editing", category); } +function onOpenCreateByParentModal(category: CategoryTree) { + emit("open-create-by-parent", category); +} + function onDelete(category: CategoryTree) { emit("delete", category); } @@ -117,6 +122,9 @@ function onDelete(category: CategoryTree) { > {{ $t("core.common.buttons.edit") }} + + {{ $t("core.post_category.operations.add_sub_category.button") }} +