mirror of https://github.com/halo-dev/halo
feat: add some formkit custom input for the system core extensions (halo-dev/console#643)
#### What type of PR is this? /kind feature /milestone 2.0 #### What this PR does / why we need it: Ref https://github.com/halo-dev/halo/issues/2526#issuecomment-1273094868 FormKit 文档:https://formkit.com/advanced/custom-inputs 通过扩展 FormKit 的自定义 Input,提供系统常用资源的选择组件。 目前提供如下类型: - menuCheckbox - menuRadio - menuItemSelect - postSelect - categorySelect - tagSelect - singlePageSelect - categoryCheckbox - tagCheckbox FormKit 组件的使用方式: ```vue <FormKit placeholder="请选择文章" label="文章" type="postSelect" validation="required" /> ``` FormKit Schema 的使用方式: ```yaml - $formkit: menuRadio name: menus label: 底部菜单组 ``` #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/2526 #### Screenshots: <!-- 如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。 If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR. eg. Before: ![screenshot-before](https://user-images.githubusercontent.com/screenshot.png) After: ![screenshot-after](https://user-images.githubusercontent.com/screenshot.png) --> #### Special notes for your reviewer: /cc @halo-dev/sig-halo-console 测试方式: 1. 检查后台文章设置弹框的选择分类和标签功能是否正常。 2. 检查后台添加菜单项的功能是否正常。 3. 使用主题或者插件定义 settings.yaml,使用上述任意 input 类型,检查得到的效果和值是否正常。 #### Does this PR introduce a user-facing change? ```release-note 通过扩展 FormKit 的自定义 Input,提供系统常用资源的选择组件。 ```pull/3445/head
parent
aa2aa26981
commit
a0512e43bc
|
@ -0,0 +1,45 @@
|
|||
# 自定义 FormKit 输入组件
|
||||
|
||||
## 原由
|
||||
|
||||
目前不管是在 Console 中,还是在插件 / 主题设置表单中,都有可能选择系统当中的资源,所以可以通过自定义 FormKit 组件的方式提供常用的选择器。
|
||||
|
||||
## 使用方式
|
||||
|
||||
目前已提供以下类型:
|
||||
|
||||
- `menuCheckbox`:选择一组菜单
|
||||
- `menuRadio`:选择一个菜单
|
||||
- `menuItemSelect`:选择菜单项
|
||||
- `postSelect`:选择文章
|
||||
- `singlePageSelect`:选择自定义页面
|
||||
- `categorySelect`:选择分类
|
||||
- `categoryCheckbox`:选择多个分类
|
||||
- `tagSelect`:选择标签
|
||||
- `tagCheckbox`:选择多个标签
|
||||
|
||||
在 Vue 单组件中使用:
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
const postName = ref("")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormKit
|
||||
v-model="postName"
|
||||
placeholder="请选择文章"
|
||||
label="文章"
|
||||
type="postSelect"
|
||||
validation="required"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
在 FormKit Schema 中使用(插件 / 主题设置表单定义):
|
||||
|
||||
```yaml
|
||||
- $formkit: menuRadio
|
||||
name: menus
|
||||
label: 底部菜单组
|
||||
```
|
|
@ -4,6 +4,15 @@ import { createAutoAnimatePlugin } from "@formkit/addons";
|
|||
import { zh } from "@formkit/i18n";
|
||||
import type { DefaultConfigOptions } from "@formkit/vue";
|
||||
import { form } from "./inputs/form";
|
||||
import { menuCheckbox } from "./inputs/menu-checkbox";
|
||||
import { menuRadio } from "./inputs/menu-radio";
|
||||
import { menuItemSelect } from "./inputs/menu-item-select";
|
||||
import { postSelect } from "./inputs/post-select";
|
||||
import { singlePageSelect } from "./inputs/singlePage-select";
|
||||
import { categorySelect } from "./inputs/category-select";
|
||||
import { tagSelect } from "./inputs/tag-select";
|
||||
import { categoryCheckbox } from "./inputs/category-checkbox";
|
||||
import { tagCheckbox } from "./inputs/tag-checkbox";
|
||||
|
||||
const config: DefaultConfigOptions = {
|
||||
config: {
|
||||
|
@ -12,6 +21,15 @@ const config: DefaultConfigOptions = {
|
|||
plugins: [createAutoAnimatePlugin()],
|
||||
inputs: {
|
||||
form,
|
||||
menuCheckbox,
|
||||
menuRadio,
|
||||
menuItemSelect,
|
||||
postSelect,
|
||||
categorySelect,
|
||||
tagSelect,
|
||||
singlePageSelect,
|
||||
categoryCheckbox,
|
||||
tagCheckbox,
|
||||
},
|
||||
locales: { zh },
|
||||
locale: "zh",
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { checkbox, checkboxes, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.category.listcontentHaloRunV1alpha1Category();
|
||||
|
||||
node.props.options = data.items.map((category) => {
|
||||
return {
|
||||
value: category.metadata.name,
|
||||
label: category.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const categoryCheckbox: FormKitTypeDefinition = {
|
||||
...checkbox,
|
||||
props: ["onValue", "offValue"],
|
||||
forceTypeProp: "checkbox",
|
||||
features: [
|
||||
optionsHandler,
|
||||
checkboxes,
|
||||
defaultIcon("decorator", "checkboxDecorator"),
|
||||
],
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { select, selects, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.category.listcontentHaloRunV1alpha1Category();
|
||||
|
||||
node.props.options = data.items.map((category) => {
|
||||
return {
|
||||
value: category.metadata.name,
|
||||
label: category.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const categorySelect: FormKitTypeDefinition = {
|
||||
...select,
|
||||
props: ["placeholder"],
|
||||
forceTypeProp: "select",
|
||||
features: [optionsHandler, selects, defaultIcon("select", "select")],
|
||||
};
|
|
@ -31,6 +31,7 @@ export const form: FormKitTypeDefinition = {
|
|||
"submitBehavior",
|
||||
"incompleteMessage",
|
||||
],
|
||||
forceTypeProp: "form",
|
||||
/**
|
||||
* Additional features that should be added to your input
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { checkbox, checkboxes, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } = await apiClient.extension.menu.listv1alpha1Menu();
|
||||
|
||||
node.props.options = data.items.map((menu) => {
|
||||
return {
|
||||
value: menu.metadata.name,
|
||||
label: menu.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const menuCheckbox: FormKitTypeDefinition = {
|
||||
...checkbox,
|
||||
props: ["onValue", "offValue"],
|
||||
forceTypeProp: "checkbox",
|
||||
features: [
|
||||
optionsHandler,
|
||||
checkboxes,
|
||||
defaultIcon("decorator", "checkboxDecorator"),
|
||||
],
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { select, selects, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } = await apiClient.extension.menuItem.listv1alpha1MenuItem({
|
||||
fieldSelector: [`name=(${node.props.menuItems.join(",")})`],
|
||||
});
|
||||
|
||||
node.props.options = data.items.map((menuItem) => {
|
||||
return {
|
||||
value: menuItem.metadata.name,
|
||||
label: menuItem.status?.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const menuItemSelect: FormKitTypeDefinition = {
|
||||
...select,
|
||||
props: ["placeholder", "menuItems"],
|
||||
forceTypeProp: "select",
|
||||
features: [optionsHandler, selects, defaultIcon("select", "select")],
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { radio, radios, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } = await apiClient.extension.menu.listv1alpha1Menu();
|
||||
|
||||
node.props.options = data.items.map((menu) => {
|
||||
return {
|
||||
value: menu.metadata.name,
|
||||
label: menu.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const menuRadio: FormKitTypeDefinition = {
|
||||
...radio,
|
||||
props: ["onValue", "offValue"],
|
||||
forceTypeProp: "radio",
|
||||
features: [
|
||||
optionsHandler,
|
||||
radios,
|
||||
defaultIcon("decorator", "radioDecorator"),
|
||||
],
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { select, selects, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.post.listcontentHaloRunV1alpha1Post();
|
||||
|
||||
node.props.options = data.items.map((post) => {
|
||||
return {
|
||||
value: post.metadata.name,
|
||||
label: post.spec.title,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const postSelect: FormKitTypeDefinition = {
|
||||
...select,
|
||||
props: ["placeholder"],
|
||||
forceTypeProp: "select",
|
||||
features: [optionsHandler, selects, defaultIcon("select", "select")],
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { select, selects, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.singlePage.listcontentHaloRunV1alpha1SinglePage();
|
||||
|
||||
node.props.options = data.items.map((singlePage) => {
|
||||
return {
|
||||
value: singlePage.metadata.name,
|
||||
label: singlePage.spec.title,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const singlePageSelect: FormKitTypeDefinition = {
|
||||
...select,
|
||||
props: ["placeholder"],
|
||||
forceTypeProp: "select",
|
||||
features: [optionsHandler, selects, defaultIcon("select", "select")],
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { checkbox, checkboxes, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.tag.listcontentHaloRunV1alpha1Tag();
|
||||
|
||||
node.props.options = data.items.map((tag) => {
|
||||
return {
|
||||
value: tag.metadata.name,
|
||||
label: tag.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const tagCheckbox: FormKitTypeDefinition = {
|
||||
...checkbox,
|
||||
props: ["onValue", "offValue"],
|
||||
forceTypeProp: "checkbox",
|
||||
features: [
|
||||
optionsHandler,
|
||||
checkboxes,
|
||||
defaultIcon("decorator", "checkboxDecorator"),
|
||||
],
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
|
||||
import { select, selects, defaultIcon } from "@formkit/inputs";
|
||||
|
||||
function optionsHandler(node: FormKitNode) {
|
||||
node.on("created", async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.tag.listcontentHaloRunV1alpha1Tag();
|
||||
|
||||
node.props.options = data.items.map((tag) => {
|
||||
return {
|
||||
value: tag.metadata.name,
|
||||
label: tag.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const tagSelect: FormKitTypeDefinition = {
|
||||
...select,
|
||||
props: ["placeholder"],
|
||||
forceTypeProp: "select",
|
||||
features: [optionsHandler, selects, defaultIcon("select", "select")],
|
||||
};
|
|
@ -1,10 +1,8 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VModal, VSpace, VTabItem, VTabs } from "@halo-dev/components";
|
||||
import { computed, ref, watch, watchEffect } from "vue";
|
||||
import { computed, ref, watchEffect } from "vue";
|
||||
import type { PostRequest } from "@halo-dev/api-client";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag";
|
||||
import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
|
@ -67,26 +65,6 @@ const saving = ref(false);
|
|||
const publishing = ref(false);
|
||||
const publishCanceling = ref(false);
|
||||
|
||||
const { categories, handleFetchCategories } = usePostCategory();
|
||||
const categoriesMap = computed(() => {
|
||||
return categories.value.map((category) => {
|
||||
return {
|
||||
value: category.metadata.name,
|
||||
label: category.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const { tags, handleFetchTags } = usePostTag();
|
||||
const tagsMap = computed(() => {
|
||||
return tags.value.map((tag) => {
|
||||
return {
|
||||
value: tag.metadata.name,
|
||||
label: tag.spec.displayName,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const isUpdateMode = computed(() => {
|
||||
return !!formState.value.post.metadata.creationTimestamp;
|
||||
});
|
||||
|
@ -180,16 +158,6 @@ const handlePublishCanceling = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
handleFetchCategories();
|
||||
handleFetchTags();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.post) {
|
||||
formState.value = cloneDeep(props.post);
|
||||
|
@ -233,17 +201,15 @@ watchEffect(() => {
|
|||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.post.spec.categories"
|
||||
:options="categoriesMap"
|
||||
label="分类目录"
|
||||
name="categories"
|
||||
type="checkbox"
|
||||
type="categoryCheckbox"
|
||||
/>
|
||||
<FormKit
|
||||
v-model="formState.post.spec.tags"
|
||||
:options="tagsMap"
|
||||
label="标签"
|
||||
name="tags"
|
||||
type="checkbox"
|
||||
type="tagCheckbox"
|
||||
/>
|
||||
<FormKit
|
||||
v-model="formState.post.spec.excerpt.autoGenerate"
|
||||
|
|
|
@ -2,15 +2,12 @@
|
|||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import type { Menu, MenuItem, Post, SinglePage } from "@halo-dev/api-client";
|
||||
import type { Menu, MenuItem } from "@halo-dev/api-client";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { reset } from "@formkit/core";
|
||||
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<{
|
||||
|
@ -47,7 +44,6 @@ const initialFormState: MenuItem = {
|
|||
},
|
||||
};
|
||||
|
||||
const menuItemMap = ref<FormKitOptionsProp>();
|
||||
const selectedParentMenuItem = ref<string>("");
|
||||
const formState = ref<MenuItem>(cloneDeep(initialFormState));
|
||||
const saving = ref(false);
|
||||
|
@ -56,25 +52,6 @@ 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;
|
||||
|
@ -244,104 +221,11 @@ const menuItemSources: MenuItemSource[] = [
|
|||
|
||||
const selectedMenuItemSource = ref<string>(menuItemSources[0].value);
|
||||
|
||||
const { categories, handleFetchCategories } = usePostCategory();
|
||||
const { tags, handleFetchTags } = usePostTag();
|
||||
const posts = ref<Post[]>([] as Post[]);
|
||||
const singlePages = ref<SinglePage[]>([] as SinglePage[]);
|
||||
|
||||
const postMap = computed(() => {
|
||||
return [
|
||||
{ label: "请选择文章", value: undefined },
|
||||
...posts.value.map((post) => {
|
||||
return {
|
||||
label: post.spec.title,
|
||||
value: post.metadata.name,
|
||||
};
|
||||
}),
|
||||
];
|
||||
});
|
||||
|
||||
const singlePageMap = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: "请选择自定义页面",
|
||||
value: undefined,
|
||||
},
|
||||
...singlePages.value.map((singlePage) => {
|
||||
return {
|
||||
label: singlePage.spec.title,
|
||||
value: singlePage.metadata.name,
|
||||
};
|
||||
}),
|
||||
];
|
||||
});
|
||||
|
||||
const categoryMap = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: "请选择分类",
|
||||
value: undefined,
|
||||
},
|
||||
...categories.value.map((category) => {
|
||||
return {
|
||||
label: category.spec.displayName,
|
||||
value: category.metadata.name,
|
||||
};
|
||||
}),
|
||||
];
|
||||
});
|
||||
|
||||
const tagMap = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: "请选择标签",
|
||||
value: undefined,
|
||||
},
|
||||
...tags.value.map((tag) => {
|
||||
return {
|
||||
label: tag.spec.displayName,
|
||||
value: tag.metadata.name,
|
||||
};
|
||||
}),
|
||||
];
|
||||
});
|
||||
|
||||
const selectedRef = ref<string>("");
|
||||
|
||||
const handleFetchPosts = async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.post.listcontentHaloRunV1alpha1Post({
|
||||
page: 0,
|
||||
size: 0,
|
||||
});
|
||||
posts.value = data.items;
|
||||
};
|
||||
|
||||
const handleFetchSinglePages = async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.singlePage.listcontentHaloRunV1alpha1SinglePage({
|
||||
page: 0,
|
||||
size: 0,
|
||||
});
|
||||
singlePages.value = data.items;
|
||||
};
|
||||
|
||||
const onMenuItemSourceChange = () => {
|
||||
selectedRef.value = "";
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
handleFetchMenuItems();
|
||||
handleFetchCategories();
|
||||
handleFetchTags();
|
||||
handleFetchPosts();
|
||||
handleFetchSinglePages();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<VModal
|
||||
|
@ -359,11 +243,12 @@ watch(
|
|||
@submit="handleSaveMenuItem"
|
||||
>
|
||||
<FormKit
|
||||
v-if="!isUpdateMode && menuItemMap"
|
||||
v-if="!isUpdateMode && menu"
|
||||
v-model="selectedParentMenuItem"
|
||||
label="上级菜单项"
|
||||
type="select"
|
||||
:options="menuItemMap"
|
||||
placeholder="选择上级菜单项"
|
||||
type="menuItemSelect"
|
||||
:menu-items="menu?.spec.menuItems || []"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
|
@ -397,9 +282,9 @@ watch(
|
|||
<FormKit
|
||||
v-if="selectedMenuItemSource === 'post'"
|
||||
v-model="selectedRef"
|
||||
placeholder="请选择文章"
|
||||
label="文章"
|
||||
type="select"
|
||||
:options="postMap"
|
||||
type="postSelect"
|
||||
validation="required"
|
||||
/>
|
||||
|
||||
|
@ -407,26 +292,25 @@ watch(
|
|||
v-if="selectedMenuItemSource === 'singlePage'"
|
||||
v-model="selectedRef"
|
||||
label="自定义页面"
|
||||
type="select"
|
||||
:options="singlePageMap"
|
||||
type="singlePageSelect"
|
||||
validation="required"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
v-if="selectedMenuItemSource === 'tag'"
|
||||
v-model="selectedRef"
|
||||
placeholder="请选择标签"
|
||||
label="标签"
|
||||
type="select"
|
||||
:options="tagMap"
|
||||
type="tagSelect"
|
||||
validation="required"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
v-if="selectedMenuItemSource === 'category'"
|
||||
v-model="selectedRef"
|
||||
placeholder="请选择分类"
|
||||
label="分类"
|
||||
type="select"
|
||||
:options="categoryMap"
|
||||
type="categorySelect"
|
||||
validation="required"
|
||||
/>
|
||||
</FormKit>
|
||||
|
|
Loading…
Reference in New Issue