perf: auto focus when opening editing forms

pull/609/head
Ryan Wang 2022-09-09 21:48:07 +08:00
parent daaf5bcf7a
commit ce93d9813b
14 changed files with 216 additions and 125 deletions

View File

@ -0,0 +1,9 @@
export function setFocus(id: string) {
const inputElement = document.getElementById(id);
if (inputElement instanceof HTMLInputElement) {
const timer = setTimeout(() => {
inputElement?.focus();
clearTimeout(timer);
}, 0);
}
}

View File

@ -7,6 +7,7 @@ import cloneDeep from "lodash.clonedeep";
import { apiClient } from "@halo-dev/admin-shared"; import { apiClient } from "@halo-dev/admin-shared";
import { reset, submitForm } from "@formkit/core"; import { reset, submitForm } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -95,7 +96,9 @@ watchEffect(() => {
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (!visible) { if (visible) {
setFocus("displayNameInput");
} else {
handleResetForm(); handleResetForm();
} }
} }
@ -119,8 +122,14 @@ watch(
:width="500" :width="500"
@update:visible="onVisibleChange" @update:visible="onVisibleChange"
> >
<FormKit id="attachment-group-form" type="form" @submit="handleSave">
<FormKit <FormKit
id="attachment-group-form"
:config="{ validationVisibility: 'submit' }"
type="form"
@submit="handleSave"
>
<FormKit
id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
label="名称" label="名称"
type="text" type="text"

View File

@ -133,7 +133,7 @@ onMounted(async () => {
</span> </span>
</div> </div>
<FloatingDropdown v-if="!readonly"> <FloatingDropdown v-if="!readonly">
<IconMore /> <IconMore @click.stop />
<template #popper> <template #popper>
<div class="w-48 p-2"> <div class="w-48 p-2">
<VSpace class="w-full" direction="column"> <VSpace class="w-full" direction="column">

View File

@ -7,6 +7,7 @@ import { apiClient, useSettingForm } from "@halo-dev/admin-shared";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { reset, submitForm } from "@formkit/core"; import { reset, submitForm } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -135,11 +136,14 @@ watchEffect(() => {
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (!visible) { if (visible) {
setTimeout(() => { setFocus("displayNameInput");
} else {
const timer = setTimeout(() => {
policyTemplate.value = undefined; policyTemplate.value = undefined;
handleResetForm(); handleResetForm();
handleResetSettingForm(); handleResetSettingForm();
clearTimeout(timer);
}, 100); }, 100);
} }
} }
@ -192,9 +196,11 @@ const onVisibleChange = (visible: boolean) => {
:actions="false" :actions="false"
:preserve="true" :preserve="true"
type="form" type="form"
:config="{ validationVisibility: 'submit' }"
@submit="handleSave" @submit="handleSave"
> >
<FormKit <FormKit
id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
label="名称" label="名称"
type="text" type="text"

View File

@ -12,6 +12,7 @@ import type { Category } from "@halo-dev/api-client";
// libs // libs
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core"; import { reset, submitForm } from "@formkit/core";
import { setFocus } from "@/formkit/utils/focus";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
@ -105,7 +106,9 @@ watchEffect(() => {
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (!visible) { if (visible) {
setFocus("displayNameInput");
} else {
handleResetForm(); handleResetForm();
} }
} }
@ -129,8 +132,14 @@ watch(
:width="600" :width="600"
@update:visible="onVisibleChange" @update:visible="onVisibleChange"
> >
<FormKit id="category-form" type="form" @submit="handleSaveCategory">
<FormKit <FormKit
id="category-form"
type="form"
:config="{ validationVisibility: 'submit' }"
@submit="handleSaveCategory"
>
<FormKit
id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
label="名称" label="名称"
type="text" type="text"

View File

@ -9,7 +9,7 @@ import { useRouter } from "vue-router";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
tag: Tag; tag: Tag;
route: boolean; route?: boolean;
}>(), }>(),
{ {
route: false, route: false,

View File

@ -18,6 +18,7 @@ import type { Tag } from "@halo-dev/api-client";
// libs // libs
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core"; import { reset, submitForm } from "@formkit/core";
import { setFocus } from "@/formkit/utils/focus";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
@ -109,7 +110,9 @@ watchEffect(() => {
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (!visible) { if (visible) {
setFocus("displayNameInput");
} else {
handleResetForm(); handleResetForm();
} }
} }
@ -141,8 +144,14 @@ watch(
<IconArrowRight /> <IconArrowRight />
</div> </div>
</template> </template>
<FormKit id="tag-form" type="form" @submit="handleSaveTag">
<FormKit <FormKit
id="tag-form"
:config="{ validationVisibility: 'submit' }"
type="form"
@submit="handleSaveTag"
>
<FormKit
id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
label="名称" label="名称"
type="text" type="text"

View File

@ -2,11 +2,12 @@
import { VButton, VModal, VSpace } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import type { Menu } from "@halo-dev/api-client"; import type { Menu } from "@halo-dev/api-client";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { computed, ref, watch } from "vue"; import { computed, ref, watch, watchEffect } from "vue";
import { apiClient } from "@halo-dev/admin-shared"; import { apiClient } from "@halo-dev/admin-shared";
import { reset, submitForm } from "@formkit/core"; import { reset, submitForm } from "@formkit/core";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -73,27 +74,41 @@ const onVisibleChange = (visible: boolean) => {
} }
}; };
watch(props, (newVal) => { const handleResetForm = () => {
const { Command_Enter } = useMagicKeys();
let keyboardWatcher;
if (newVal.visible) {
keyboardWatcher = watch(Command_Enter, (v) => {
if (v) {
submitForm("menu-form");
}
});
} else {
keyboardWatcher?.unwatch();
}
if (newVal.visible && props.menu) {
formState.value = cloneDeep(props.menu);
return;
}
formState.value = cloneDeep(initialFormState); formState.value = cloneDeep(initialFormState);
formState.value.metadata.name = uuid(); formState.value.metadata.name = uuid();
reset("menu-form"); reset("menu-form");
};
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("menu-form");
}
}); });
watch(
() => props.visible,
(visible) => {
if (visible) {
setFocus("displayNameInput");
} else {
handleResetForm();
}
}
);
watch(
() => props.menu,
(menu) => {
if (menu) {
formState.value = cloneDeep(menu);
} else {
handleResetForm();
}
}
);
</script> </script>
<template> <template>
<VModal <VModal
@ -106,9 +121,11 @@ watch(props, (newVal) => {
id="menu-form" id="menu-form"
:classes="{ form: 'w-full' }" :classes="{ form: 'w-full' }"
type="form" type="form"
:config="{ validationVisibility: 'submit' }"
@submit="handleCreateMenu" @submit="handleCreateMenu"
> >
<FormKit <FormKit
id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
help="可根据此名称查询菜单项" help="可根据此名称查询菜单项"
label="菜单名称" label="菜单名称"

View File

@ -9,6 +9,7 @@ import cloneDeep from "lodash.clonedeep";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category"; import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category";
import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag"; import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag";
import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -114,7 +115,9 @@ watchEffect(() => {
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (!visible) { if (visible) {
setFocus("displayNameInput");
} else {
handleResetForm(); handleResetForm();
} }
} }
@ -301,7 +304,12 @@ watch(
title="编辑菜单项" title="编辑菜单项"
@update:visible="onVisibleChange" @update:visible="onVisibleChange"
> >
<FormKit id="menuitem-form" type="form" @submit="handleSaveMenuItem"> <FormKit
id="menuitem-form"
type="form"
:config="{ validationVisibility: 'submit' }"
@submit="handleSaveMenuItem"
>
<FormKit <FormKit
v-model="selectedMenuItemSource" v-model="selectedMenuItemSource"
:options="menuItemSources" :options="menuItemSources"
@ -314,6 +322,7 @@ watch(
<FormKit <FormKit
v-if="selectedMenuItemSource === 'custom'" v-if="selectedMenuItemSource === 'custom'"
id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
label="名称" label="名称"
type="text" type="text"

View File

@ -11,6 +11,7 @@ import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core"; import { reset, submitForm } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -60,7 +61,9 @@ watchEffect(() => {
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (!visible) { if (visible) {
setFocus("displayNameInput");
} else {
handleResetForm(); handleResetForm();
} }
} }
@ -124,9 +127,11 @@ const handleResetForm = () => {
id="role-form" id="role-form"
:actions="false" :actions="false"
type="form" type="form"
:config="{ validationVisibility: 'submit' }"
@submit="handleCreateOrUpdateRole" @submit="handleCreateOrUpdateRole"
> >
<FormKit <FormKit
id="displayNameInput"
v-model=" v-model="
formState.metadata.annotations[rbacAnnotations.DISPLAY_NAME] formState.metadata.annotations[rbacAnnotations.DISPLAY_NAME]
" "
@ -139,6 +144,7 @@ const handleResetForm = () => {
help="角色别名,用于区分角色,不能重复,创建之后不能修改" help="角色别名,用于区分角色,不能重复,创建之后不能修改"
label="别名" label="别名"
type="text" type="text"
:disabled="isUpdateMode"
validation="required" validation="required"
></FormKit> ></FormKit>
</FormKit> </FormKit>

View File

@ -10,6 +10,7 @@ export default definePlugin({
{ {
path: "/settings", path: "/settings",
component: SystemSettingsLayout, component: SystemSettingsLayout,
redirect: "/settings/basic",
children: [ children: [
{ {
path: ":group", path: ":group",
@ -25,7 +26,7 @@ export default definePlugin({
items: [ items: [
{ {
name: "设置", name: "设置",
path: "/settings/basic", path: "/settings",
icon: IconSettings, icon: IconSettings,
}, },
], ],

View File

@ -102,14 +102,12 @@ onMounted(() => {
<template> <template>
<UserEditingModal <UserEditingModal
v-model:visible="editingModal" v-model:visible="editingModal"
v-permission="['system:users:manage']"
:user="selectedUser" :user="selectedUser"
@close="onEditingModalClose" @close="onEditingModalClose"
/> />
<UserPasswordChangeModal <UserPasswordChangeModal
v-model:visible="passwordChangeModal" v-model:visible="passwordChangeModal"
v-permission="['system:users:manage']"
:user="selectedUser" :user="selectedUser"
@close="handleFetchUsers" @close="handleFetchUsers"
/> />

View File

@ -15,7 +15,6 @@ import {
} from "@halo-dev/components"; } from "@halo-dev/components";
// libs // libs
import { v4 as uuid } from "uuid";
import YAML from "yaml"; import YAML from "yaml";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { useMagicKeys } from "@vueuse/core"; import { useMagicKeys } from "@vueuse/core";
@ -27,6 +26,7 @@ import { rbacAnnotations } from "@/constants/annotations";
// hooks // hooks
import { useFetchRole } from "@/modules/system/roles/composables/use-role"; import { useFetchRole } from "@/modules/system/roles/composables/use-role";
import type { FormKitOptionsList } from "@formkit/inputs"; import type { FormKitOptionsList } from "@formkit/inputs";
import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -44,15 +44,7 @@ const emit = defineEmits<{
(event: "close"): void; (event: "close"): void;
}>(); }>();
interface FormState { const initialFormState: User = {
user: User;
saving: boolean;
rawMode: boolean;
raw: string;
}
const initialFormState: FormState = {
user: {
spec: { spec: {
displayName: "", displayName: "",
avatar: "", avatar: "",
@ -66,19 +58,18 @@ const initialFormState: FormState = {
apiVersion: "v1alpha1", apiVersion: "v1alpha1",
kind: "User", kind: "User",
metadata: { metadata: {
name: uuid(), name: "",
}, },
},
saving: false,
rawMode: false,
raw: "",
}; };
const formState = ref<FormState>(cloneDeep(initialFormState)); const formState = ref<User>(cloneDeep(initialFormState));
const saving = ref(false);
const rawMode = ref(false);
const raw = ref("");
const selectedRole = ref(""); const selectedRole = ref("");
const isUpdateMode = computed(() => { const isUpdateMode = computed(() => {
return !!formState.value.user.metadata.creationTimestamp; return !!formState.value.metadata.creationTimestamp;
}); });
const creationModalTitle = computed(() => { const creationModalTitle = computed(() => {
@ -86,7 +77,7 @@ const creationModalTitle = computed(() => {
}); });
const modalWidth = computed(() => { const modalWidth = computed(() => {
return formState.value.rawMode ? 800 : 700; return rawMode.value ? 800 : 700;
}); });
const { roles } = useFetchRole(); const { roles } = useFetchRole();
@ -112,7 +103,9 @@ watchEffect(() => {
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (!visible) { if (visible) {
setFocus(isUpdateMode.value ? "displayNameInput" : "userNameInput");
} else {
handleResetForm(); handleResetForm();
} }
} }
@ -122,7 +115,7 @@ watch(
() => props.user, () => props.user,
(user) => { (user) => {
if (user) { if (user) {
formState.value.user = cloneDeep(user); formState.value = cloneDeep(user);
} else { } else {
handleResetForm(); handleResetForm();
} }
@ -138,24 +131,23 @@ const onVisibleChange = (visible: boolean) => {
const handleResetForm = () => { const handleResetForm = () => {
formState.value = cloneDeep(initialFormState); formState.value = cloneDeep(initialFormState);
formState.value.user.metadata.name = uuid();
reset("user-form"); reset("user-form");
}; };
const handleCreateUser = async () => { const handleCreateUser = async () => {
try { try {
formState.value.saving = true; saving.value = true;
let user: User; let user: User;
if (isUpdateMode.value) { if (isUpdateMode.value) {
const response = await apiClient.extension.user.updatev1alpha1User({ const response = await apiClient.extension.user.updatev1alpha1User({
name: formState.value.user.metadata.name, name: formState.value.metadata.name,
user: formState.value.user, user: formState.value,
}); });
user = response.data; user = response.data;
} else { } else {
const response = await apiClient.extension.user.createv1alpha1User({ const response = await apiClient.extension.user.createv1alpha1User({
user: formState.value.user, user: formState.value,
}); });
user = response.data; user = response.data;
} }
@ -173,17 +165,17 @@ const handleCreateUser = async () => {
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} finally { } finally {
formState.value.saving = false; saving.value = false;
} }
}; };
const handleRawModeChange = () => { const handleRawModeChange = () => {
formState.value.rawMode = !formState.value.rawMode; rawMode.value = !rawMode.value;
if (formState.value.rawMode) { if (rawMode.value) {
formState.value.raw = YAML.stringify(formState.value.user); raw.value = YAML.stringify(formState.value);
} else { } else {
formState.value.user = YAML.parse(formState.value.raw); formState.value = YAML.parse(raw.value);
} }
}; };
</script> </script>
@ -196,35 +188,37 @@ const handleRawModeChange = () => {
> >
<template #actions> <template #actions>
<div class="modal-header-action" @click="handleRawModeChange"> <div class="modal-header-action" @click="handleRawModeChange">
<IconCodeBoxLine v-if="!formState.rawMode" /> <IconCodeBoxLine v-if="!rawMode" />
<IconEye v-else /> <IconEye v-else />
</div> </div>
</template> </template>
<VCodemirror <VCodemirror v-show="rawMode" v-model="raw" height="50vh" language="yaml" />
v-show="formState.rawMode"
v-model="formState.raw"
height="50vh"
language="yaml"
/>
<div v-show="!formState.rawMode"> <div v-show="!rawMode">
<FormKit id="user-form" type="form" @submit="handleCreateUser">
<FormKit <FormKit
v-model="formState.user.metadata.name" id="user-form"
:config="{ validationVisibility: 'submit' }"
type="form"
@submit="handleCreateUser"
>
<FormKit
id="userNameInput"
v-model="formState.metadata.name"
:disabled="isUpdateMode" :disabled="isUpdateMode"
label="用户名" label="用户名"
type="text" type="text"
validation="required" validation="required"
></FormKit> ></FormKit>
<FormKit <FormKit
v-model="formState.user.spec.displayName" id="displayNameInput"
v-model="formState.spec.displayName"
label="显示名称" label="显示名称"
type="text" type="text"
validation="required" validation="required"
></FormKit> ></FormKit>
<FormKit <FormKit
v-model="formState.user.spec.email" v-model="formState.spec.email"
label="电子邮箱" label="电子邮箱"
type="email" type="email"
validation="required" validation="required"
@ -236,17 +230,17 @@ const handleRawModeChange = () => {
type="select" type="select"
></FormKit> ></FormKit>
<FormKit <FormKit
v-model="formState.user.spec.phone" v-model="formState.spec.phone"
label="手机号" label="手机号"
type="text" type="text"
></FormKit> ></FormKit>
<FormKit <FormKit
v-model="formState.user.spec.avatar" v-model="formState.spec.avatar"
label="头像" label="头像"
type="text" type="text"
></FormKit> ></FormKit>
<FormKit <FormKit
v-model="formState.user.spec.bio" v-model="formState.spec.bio"
label="描述" label="描述"
type="textarea" type="textarea"
></FormKit> ></FormKit>
@ -255,7 +249,7 @@ const handleRawModeChange = () => {
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton <VButton
:loading="formState.saving" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('user-form')" @click="$formkit.submit('user-form')"
> >

View File

@ -1,9 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { IconSave, VButton, VModal } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import { inject, ref } from "vue"; import { inject, ref, watch, watchEffect } from "vue";
import type { User } from "@halo-dev/api-client"; import type { User } from "@halo-dev/api-client";
import { apiClient } from "@halo-dev/admin-shared"; import { apiClient } from "@halo-dev/admin-shared";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -24,35 +27,54 @@ const emit = defineEmits<{
const currentUser = inject<User>("currentUser"); const currentUser = inject<User>("currentUser");
interface PasswordChangeFormState { interface PasswordChangeFormState {
state: {
password: string; password: string;
password_confirm?: string; password_confirm?: string;
};
submitting: boolean;
} }
const formState = ref<PasswordChangeFormState>({ const initialFormState: PasswordChangeFormState = {
state: {
password: "", password: "",
password_confirm: "", password_confirm: "",
}, };
submitting: false,
const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState));
const saving = ref(false);
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("password-form");
}
}); });
const handleVisibleChange = (visible: boolean) => { watch(
() => props.visible,
(visible) => {
if (visible) {
setFocus("passwordInput");
} else {
handleResetForm();
}
}
);
const onVisibleChange = (visible: boolean) => {
emit("update:visible", visible); emit("update:visible", visible);
if (!visible) { if (!visible) {
formState.value.state.password = "";
formState.value.state.password_confirm = "";
emit("close"); emit("close");
} }
}; };
const handleResetForm = () => {
formState.value = cloneDeep(initialFormState);
reset("password-form");
};
const handleChangePassword = async () => { const handleChangePassword = async () => {
try { try {
formState.value.submitting = true; saving.value = true;
const changePasswordRequest = cloneDeep(formState.value.state); const changePasswordRequest = cloneDeep(formState.value);
delete changePasswordRequest.password_confirm; delete changePasswordRequest.password_confirm;
if (props.user?.metadata.name === currentUser?.metadata.name) { if (props.user?.metadata.name === currentUser?.metadata.name) {
@ -67,11 +89,11 @@ const handleChangePassword = async () => {
}); });
} }
handleVisibleChange(false); onVisibleChange(false);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} finally { } finally {
formState.value.submitting = false; saving.value = false;
} }
}; };
</script> </script>
@ -81,16 +103,18 @@ const handleChangePassword = async () => {
:visible="visible" :visible="visible"
:width="500" :width="500"
title="密码修改" title="密码修改"
@update:visible="handleVisibleChange" @update:visible="onVisibleChange"
> >
<FormKit <FormKit
id="password-form" id="password-form"
v-model="formState.state" v-model="formState"
:actions="false" :actions="false"
type="form" type="form"
:config="{ validationVisibility: 'submit' }"
@submit="handleChangePassword" @submit="handleChangePassword"
> >
<FormKit <FormKit
id="passwordInput"
label="新密码" label="新密码"
name="password" name="password"
type="password" type="password"
@ -104,16 +128,16 @@ const handleChangePassword = async () => {
></FormKit> ></FormKit>
</FormKit> </FormKit>
<template #footer> <template #footer>
<VSpace>
<VButton <VButton
:loading="formState.submitting" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('password-form')" @click="$formkit.submit('password-form')"
> >
<template #icon> 提交 +
<IconSave class="h-full w-full" />
</template>
保存
</VButton> </VButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace>
</template> </template>
</VModal> </VModal>
</template> </template>