mirror of https://github.com/halo-dev/halo-admin
feat: add annotations form for more extension (#801)
#### What type of PR is this? /kind feature #### What this PR does / why we need it: 为更多模型添加 Annotation Form 的支持。此 PR 包括: 1. 自定义页面。 2. 文章分类。 3. 文章标签。 4. 菜单项。 5. 用户。 此 PR 是对 https://github.com/halo-dev/console/pull/770 的补充。 #### Special notes for your reviewer: 测试方式: 1. 将一下内容放到任意一个主题下,后缀为 `yaml`,文件名随意。 ```yaml spec: targetRef: group: content.halo.run kind: Post formSchema: - $formkit: "text" name: "download" label: "下载地址" - $formkit: "text" name: "version" label: "版本" apiVersion: v1alpha1 kind: AnnotationSetting metadata: generateName: annotation- --- spec: targetRef: group: content.halo.run kind: SinglePage formSchema: - $formkit: "text" name: "download" label: "下载地址" - $formkit: "text" name: "version" label: "版本" apiVersion: v1alpha1 kind: AnnotationSetting metadata: generateName: annotation- --- spec: targetRef: group: content.halo.run kind: Category formSchema: - $formkit: "text" name: "download" label: "下载地址" - $formkit: "text" name: "version" label: "版本" apiVersion: v1alpha1 kind: AnnotationSetting metadata: generateName: annotation- --- spec: targetRef: group: content.halo.run kind: Tag formSchema: - $formkit: "text" name: "download" label: "下载地址" - $formkit: "text" name: "version" label: "版本" apiVersion: v1alpha1 kind: AnnotationSetting metadata: generateName: annotation- --- spec: targetRef: group: "" kind: MenuItem formSchema: - $formkit: "text" name: "icon" label: "图标" - $formkit: "text" name: "version" label: "版本" apiVersion: v1alpha1 kind: AnnotationSetting metadata: generateName: annotation- ``` 3. 后端需要使用 https://github.com/halo-dev/halo/pull/3028 4. 测试上述提到的模型的 Annotations 表单。 5. 检查是否可以设置正常。 #### Does this PR introduce a user-facing change? ```release-note None ```pull/802/head
parent
d60931bae5
commit
8d3c289559
|
@ -148,7 +148,11 @@ const specFormInvalid = ref(true);
|
|||
const customFormInvalid = ref(true);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
submitForm("specForm");
|
||||
if (avaliableAnnotationSettings.value.length) {
|
||||
submitForm("specForm");
|
||||
} else {
|
||||
specFormInvalid.value = false;
|
||||
}
|
||||
submitForm("customForm");
|
||||
await nextTick();
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ import { singlePageLabels } from "@/constants/labels";
|
|||
import { randomUUID } from "@/utils/id";
|
||||
import { toDatetimeLocal, toISOString } from "@/utils/date";
|
||||
import { submitForm } from "@formkit/core";
|
||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||
|
||||
const initialFormState: SinglePage = {
|
||||
spec: {
|
||||
|
@ -75,6 +76,8 @@ const onVisibleChange = (visible: boolean) => {
|
|||
}
|
||||
};
|
||||
|
||||
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (submitType.value === "publish") {
|
||||
handlePublish();
|
||||
|
@ -101,6 +104,20 @@ const handlePublishClick = () => {
|
|||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
annotationsFormRef.value?.handleSubmit();
|
||||
await nextTick();
|
||||
|
||||
const { customAnnotations, annotations, customFormInvalid, specFormInvalid } =
|
||||
annotationsFormRef.value || {};
|
||||
if (customFormInvalid || specFormInvalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
formState.value.metadata.annotations = {
|
||||
...annotations,
|
||||
...customAnnotations,
|
||||
};
|
||||
|
||||
if (props.onlyEmit) {
|
||||
emit("saved", formState.value);
|
||||
return;
|
||||
|
@ -138,6 +155,20 @@ const handleSave = async () => {
|
|||
};
|
||||
|
||||
const handlePublish = async () => {
|
||||
annotationsFormRef.value?.handleSubmit();
|
||||
await nextTick();
|
||||
|
||||
const { customAnnotations, annotations, customFormInvalid, specFormInvalid } =
|
||||
annotationsFormRef.value || {};
|
||||
if (customFormInvalid || specFormInvalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
formState.value.metadata.annotations = {
|
||||
...annotations,
|
||||
...customAnnotations,
|
||||
};
|
||||
|
||||
if (props.onlyEmit) {
|
||||
emit("published", formState.value);
|
||||
return;
|
||||
|
@ -364,6 +395,27 @@ const onPublishTimeChange = (value: string) => {
|
|||
</div>
|
||||
</FormKit>
|
||||
|
||||
<div class="py-5">
|
||||
<div class="border-t border-gray-200"></div>
|
||||
</div>
|
||||
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 元数据 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<AnnotationsForm
|
||||
:key="formState.metadata.name"
|
||||
ref="annotationsFormRef"
|
||||
:value="formState.metadata.annotations"
|
||||
kind="SinglePage"
|
||||
group="content.halo.run"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<template v-if="publishSupport">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { computed, nextTick, ref, watch } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
|
||||
// components
|
||||
|
@ -15,6 +15,7 @@ import cloneDeep from "lodash.clonedeep";
|
|||
import { reset } from "@formkit/core";
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import { useThemeCustomTemplates } from "@/modules/interface/themes/composables/use-theme";
|
||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -62,7 +63,23 @@ const modalTitle = computed(() => {
|
|||
return isUpdateMode.value ? "编辑文章分类" : "新增文章分类";
|
||||
});
|
||||
|
||||
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||
|
||||
const handleSaveCategory = async () => {
|
||||
annotationsFormRef.value?.handleSubmit();
|
||||
await nextTick();
|
||||
|
||||
const { customAnnotations, annotations, customFormInvalid, specFormInvalid } =
|
||||
annotationsFormRef.value || {};
|
||||
if (customFormInvalid || specFormInvalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
formState.value.metadata.annotations = {
|
||||
...annotations,
|
||||
...customAnnotations,
|
||||
};
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
if (isUpdateMode.value) {
|
||||
|
@ -126,56 +143,89 @@ const { templates } = useThemeCustomTemplates("category");
|
|||
<VModal
|
||||
:title="modalTitle"
|
||||
:visible="visible"
|
||||
:width="600"
|
||||
:width="700"
|
||||
@update:visible="onVisibleChange"
|
||||
>
|
||||
<FormKit
|
||||
id="category-form"
|
||||
name="category-form"
|
||||
type="form"
|
||||
name="category-form"
|
||||
:config="{ validationVisibility: 'submit' }"
|
||||
@submit="handleSaveCategory"
|
||||
>
|
||||
<FormKit
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
name="displayName"
|
||||
label="名称"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.slug"
|
||||
help="通常作为分类访问地址标识"
|
||||
name="slug"
|
||||
label="别名"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.template"
|
||||
:options="templates"
|
||||
label="自定义模板"
|
||||
type="select"
|
||||
name="template"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.cover"
|
||||
help="需要主题适配以支持"
|
||||
name="cover"
|
||||
label="封面图"
|
||||
type="attachment"
|
||||
validation="length:0,1024"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.description"
|
||||
name="description"
|
||||
help="需要主题适配以支持"
|
||||
label="描述"
|
||||
type="textarea"
|
||||
validation="length:0,200"
|
||||
></FormKit>
|
||||
<div>
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 常规 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<FormKit
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
name="displayName"
|
||||
label="名称"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.slug"
|
||||
help="通常作为分类访问地址标识"
|
||||
name="slug"
|
||||
label="别名"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.template"
|
||||
:options="templates"
|
||||
label="自定义模板"
|
||||
type="select"
|
||||
name="template"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.cover"
|
||||
help="需要主题适配以支持"
|
||||
name="cover"
|
||||
label="封面图"
|
||||
type="attachment"
|
||||
validation="length:0,1024"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.description"
|
||||
name="description"
|
||||
help="需要主题适配以支持"
|
||||
label="描述"
|
||||
type="textarea"
|
||||
validation="length:0,200"
|
||||
></FormKit>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormKit>
|
||||
|
||||
<div class="py-5">
|
||||
<div class="border-t border-gray-200"></div>
|
||||
</div>
|
||||
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 元数据 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<AnnotationsForm
|
||||
:key="formState.metadata.name"
|
||||
ref="annotationsFormRef"
|
||||
:value="formState.metadata.annotations"
|
||||
kind="Category"
|
||||
group="content.halo.run"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { computed, nextTick, ref, watch } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
|
||||
// components
|
||||
|
@ -21,6 +21,7 @@ import type { Tag } from "@halo-dev/api-client";
|
|||
import cloneDeep from "lodash.clonedeep";
|
||||
import { reset } from "@formkit/core";
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -66,7 +67,23 @@ const modalTitle = computed(() => {
|
|||
return isUpdateMode.value ? "编辑文章标签" : "新增文章标签";
|
||||
});
|
||||
|
||||
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||
|
||||
const handleSaveTag = async () => {
|
||||
annotationsFormRef.value?.handleSubmit();
|
||||
await nextTick();
|
||||
|
||||
const { customAnnotations, annotations, customFormInvalid, specFormInvalid } =
|
||||
annotationsFormRef.value || {};
|
||||
if (customFormInvalid || specFormInvalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
formState.value.metadata.annotations = {
|
||||
...annotations,
|
||||
...customAnnotations,
|
||||
};
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
if (isUpdateMode.value) {
|
||||
|
@ -127,7 +144,7 @@ watch(
|
|||
<VModal
|
||||
:title="modalTitle"
|
||||
:visible="visible"
|
||||
:width="600"
|
||||
:width="700"
|
||||
@update:visible="onVisibleChange"
|
||||
>
|
||||
<template #actions>
|
||||
|
@ -138,46 +155,80 @@ watch(
|
|||
<IconArrowRight />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<FormKit
|
||||
id="tag-form"
|
||||
type="form"
|
||||
name="tag-form"
|
||||
:config="{ validationVisibility: 'submit' }"
|
||||
type="form"
|
||||
@submit="handleSaveTag"
|
||||
>
|
||||
<FormKit
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
name="displayName"
|
||||
label="名称"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.slug"
|
||||
help="通常作为标签访问地址标识"
|
||||
label="别名"
|
||||
name="slug"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.color"
|
||||
name="color"
|
||||
help="需要主题适配以支持"
|
||||
label="颜色"
|
||||
type="color"
|
||||
validation="length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.cover"
|
||||
name="cover"
|
||||
help="需要主题适配以支持"
|
||||
label="封面图"
|
||||
type="attachment"
|
||||
validation="length:0,1024"
|
||||
></FormKit>
|
||||
<div>
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 常规 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<FormKit
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
name="displayName"
|
||||
label="名称"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.slug"
|
||||
help="通常作为标签访问地址标识"
|
||||
label="别名"
|
||||
name="slug"
|
||||
type="text"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.color"
|
||||
name="color"
|
||||
help="需要主题适配以支持"
|
||||
label="颜色"
|
||||
type="color"
|
||||
validation="length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.cover"
|
||||
name="cover"
|
||||
help="需要主题适配以支持"
|
||||
label="封面图"
|
||||
type="attachment"
|
||||
validation="length:0,1024"
|
||||
></FormKit>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormKit>
|
||||
|
||||
<div class="py-5">
|
||||
<div class="border-t border-gray-200"></div>
|
||||
</div>
|
||||
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 元数据 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<AnnotationsForm
|
||||
:key="formState.metadata.name"
|
||||
ref="annotationsFormRef"
|
||||
:value="formState.metadata.annotations"
|
||||
kind="Tag"
|
||||
group="content.halo.run"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<script lang="ts" setup>
|
||||
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { computed, nextTick, ref, watch } from "vue";
|
||||
import type { Menu, MenuItem, Ref } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { reset } from "@formkit/core";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -56,7 +57,23 @@ const modalTitle = computed(() => {
|
|||
return isUpdateMode.value ? "编辑菜单项" : "新增菜单项";
|
||||
});
|
||||
|
||||
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||
|
||||
const handleSaveMenuItem = async () => {
|
||||
annotationsFormRef.value?.handleSubmit();
|
||||
await nextTick();
|
||||
|
||||
const { customAnnotations, annotations, customFormInvalid, specFormInvalid } =
|
||||
annotationsFormRef.value || {};
|
||||
if (customFormInvalid || specFormInvalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
formState.value.metadata.annotations = {
|
||||
...annotations,
|
||||
...customAnnotations,
|
||||
};
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
|
||||
|
@ -243,7 +260,7 @@ const onMenuItemSourceChange = () => {
|
|||
<template>
|
||||
<VModal
|
||||
:visible="visible"
|
||||
:width="500"
|
||||
:width="700"
|
||||
:title="modalTitle"
|
||||
@update:visible="onVisibleChange"
|
||||
>
|
||||
|
@ -255,54 +272,87 @@ const onMenuItemSourceChange = () => {
|
|||
:config="{ validationVisibility: 'submit' }"
|
||||
@submit="handleSaveMenuItem"
|
||||
>
|
||||
<FormKit
|
||||
v-if="!isUpdateMode && menu && visible"
|
||||
v-model="selectedParentMenuItem"
|
||||
label="上级菜单项"
|
||||
placeholder="选择上级菜单项"
|
||||
type="menuItemSelect"
|
||||
:menu-items="menu?.spec.menuItems || []"
|
||||
/>
|
||||
<div>
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 常规 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<FormKit
|
||||
v-if="!isUpdateMode && menu && visible"
|
||||
v-model="selectedParentMenuItem"
|
||||
label="上级菜单项"
|
||||
placeholder="选择上级菜单项"
|
||||
type="menuItemSelect"
|
||||
:menu-items="menu?.spec.menuItems || []"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
v-model="selectedRefKind"
|
||||
:options="menuItemRefsMap"
|
||||
:disabled="isUpdateMode"
|
||||
label="类型"
|
||||
type="select"
|
||||
@change="onMenuItemSourceChange"
|
||||
/>
|
||||
<FormKit
|
||||
v-model="selectedRefKind"
|
||||
:options="menuItemRefsMap"
|
||||
:disabled="isUpdateMode"
|
||||
label="类型"
|
||||
type="select"
|
||||
@change="onMenuItemSourceChange"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
v-if="!selectedRefKind"
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
label="名称"
|
||||
type="text"
|
||||
name="displayName"
|
||||
validation="required|length:0,100"
|
||||
/>
|
||||
<FormKit
|
||||
v-if="!selectedRefKind"
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
label="名称"
|
||||
type="text"
|
||||
name="displayName"
|
||||
validation="required|length:0,100"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
v-if="!selectedRefKind"
|
||||
v-model="formState.spec.href"
|
||||
label="链接地址"
|
||||
type="text"
|
||||
name="href"
|
||||
validation="required|length:0,1024"
|
||||
/>
|
||||
<FormKit
|
||||
v-if="!selectedRefKind"
|
||||
v-model="formState.spec.href"
|
||||
label="链接地址"
|
||||
type="text"
|
||||
name="href"
|
||||
validation="required|length:0,1024"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
v-if="selectedRef?.ref"
|
||||
:id="selectedRef.inputType"
|
||||
:key="selectedRef.inputType"
|
||||
v-model="selectedRefName"
|
||||
:placeholder="`请选择${selectedRef.label}`"
|
||||
:label="selectedRef.label"
|
||||
:type="selectedRef.inputType"
|
||||
validation="required"
|
||||
/>
|
||||
<FormKit
|
||||
v-if="selectedRef?.ref"
|
||||
:id="selectedRef.inputType"
|
||||
:key="selectedRef.inputType"
|
||||
v-model="selectedRefName"
|
||||
:placeholder="`请选择${selectedRef.label}`"
|
||||
:label="selectedRef.label"
|
||||
:type="selectedRef.inputType"
|
||||
validation="required"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormKit>
|
||||
|
||||
<div class="py-5">
|
||||
<div class="border-t border-gray-200"></div>
|
||||
</div>
|
||||
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 元数据 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<AnnotationsForm
|
||||
:key="formState.metadata.name"
|
||||
ref="annotationsFormRef"
|
||||
:value="formState.metadata.annotations"
|
||||
kind="MenuItem"
|
||||
group=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { computed, nextTick, ref, watch } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
|
||||
|
@ -14,6 +14,7 @@ import { reset } from "@formkit/core";
|
|||
|
||||
// hooks
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -94,7 +95,23 @@ const handleResetForm = () => {
|
|||
reset("user-form");
|
||||
};
|
||||
|
||||
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||
|
||||
const handleCreateUser = async () => {
|
||||
annotationsFormRef.value?.handleSubmit();
|
||||
await nextTick();
|
||||
|
||||
const { customAnnotations, annotations, customFormInvalid, specFormInvalid } =
|
||||
annotationsFormRef.value || {};
|
||||
if (customFormInvalid || specFormInvalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
formState.value.metadata.annotations = {
|
||||
...annotations,
|
||||
...customAnnotations,
|
||||
};
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
if (isUpdateMode.value) {
|
||||
|
@ -132,52 +149,84 @@ const handleCreateUser = async () => {
|
|||
type="form"
|
||||
@submit="handleCreateUser"
|
||||
>
|
||||
<FormKit
|
||||
id="userNameInput"
|
||||
v-model="formState.metadata.name"
|
||||
:disabled="isUpdateMode"
|
||||
label="用户名"
|
||||
type="text"
|
||||
name="name"
|
||||
validation="required|alphanumeric|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
label="显示名称"
|
||||
type="text"
|
||||
name="displayName"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.email"
|
||||
label="电子邮箱"
|
||||
type="email"
|
||||
name="email"
|
||||
validation="required|email|length:0,100"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.phone"
|
||||
label="手机号"
|
||||
type="text"
|
||||
name="phone"
|
||||
validation="length:0,20"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.avatar"
|
||||
label="头像"
|
||||
type="attachment"
|
||||
name="avatar"
|
||||
validation="url|length:0,1024"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.bio"
|
||||
label="描述"
|
||||
type="textarea"
|
||||
name="bio"
|
||||
validation="length:0,2048"
|
||||
></FormKit>
|
||||
<div>
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 常规 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<FormKit
|
||||
id="userNameInput"
|
||||
v-model="formState.metadata.name"
|
||||
:disabled="isUpdateMode"
|
||||
label="用户名"
|
||||
type="text"
|
||||
name="name"
|
||||
validation="required|alphanumeric|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
id="displayNameInput"
|
||||
v-model="formState.spec.displayName"
|
||||
label="显示名称"
|
||||
type="text"
|
||||
name="displayName"
|
||||
validation="required|length:0,50"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.email"
|
||||
label="电子邮箱"
|
||||
type="email"
|
||||
name="email"
|
||||
validation="required|email|length:0,100"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.phone"
|
||||
label="手机号"
|
||||
type="text"
|
||||
name="phone"
|
||||
validation="length:0,20"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.avatar"
|
||||
label="头像"
|
||||
type="attachment"
|
||||
name="avatar"
|
||||
validation="url|length:0,1024"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="formState.spec.bio"
|
||||
label="描述"
|
||||
type="textarea"
|
||||
name="bio"
|
||||
validation="length:0,2048"
|
||||
></FormKit>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormKit>
|
||||
|
||||
<div class="py-5">
|
||||
<div class="border-t border-gray-200"></div>
|
||||
</div>
|
||||
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="sticky top-0">
|
||||
<span class="text-base font-medium text-gray-900"> 元数据 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
||||
<AnnotationsForm
|
||||
:key="formState.metadata.name"
|
||||
ref="annotationsFormRef"
|
||||
:value="formState.metadata.annotations"
|
||||
kind="User"
|
||||
group=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
|
|
Loading…
Reference in New Issue