mirror of https://github.com/halo-dev/halo
refactor: improve code base of user-related (#5975)
#### What type of PR is this? /area ui /kind improvement /milestone 2.16.x #### What this PR does / why we need it: 优化和用户管理相关的所有对话框显示逻辑,减少不必要的渲染开销和请求。 #### Special notes for your reviewer: 改动范围如下: 1. 用户密码修改 2. 用户资料修改 3. 用户创建 4. 重新登录 #### Does this PR introduce a user-facing change? ```release-note 优化和用户管理相关的所有对话框显示逻辑,减少不必要的渲染开销和请求。 ```pull/5977/head
parent
c51f2f4d4f
commit
4d289c0a45
|
@ -95,14 +95,23 @@ const tabbarItems = computed(() => {
|
|||
function handleRouteToUC() {
|
||||
window.location.href = "/uc";
|
||||
}
|
||||
|
||||
function onPasswordChangeModalClose() {
|
||||
passwordChangeModal.value = false;
|
||||
refetch();
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<UserEditingModal v-model:visible="editingModal" :user="user?.user" />
|
||||
<UserEditingModal
|
||||
v-if="editingModal && user?.user"
|
||||
:user="user?.user"
|
||||
@close="editingModal = false"
|
||||
/>
|
||||
|
||||
<UserPasswordChangeModal
|
||||
v-model:visible="passwordChangeModal"
|
||||
v-if="passwordChangeModal"
|
||||
:user="user?.user"
|
||||
@close="refetch"
|
||||
@close="onPasswordChangeModalClose"
|
||||
/>
|
||||
|
||||
<header class="bg-white">
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
<script lang="ts" setup>
|
||||
import {
|
||||
Dialog,
|
||||
IconAddCircle,
|
||||
IconLockPasswordLine,
|
||||
IconRefreshLine,
|
||||
IconUserFollow,
|
||||
IconUserSettings,
|
||||
IconLockPasswordLine,
|
||||
Toast,
|
||||
VAvatar,
|
||||
VButton,
|
||||
VCard,
|
||||
VDropdownItem,
|
||||
VEmpty,
|
||||
VEntity,
|
||||
VEntityField,
|
||||
VLoading,
|
||||
VPageHeader,
|
||||
VPagination,
|
||||
VSpace,
|
||||
VTag,
|
||||
VAvatar,
|
||||
VEntity,
|
||||
VEntityField,
|
||||
Dialog,
|
||||
VStatusDot,
|
||||
VLoading,
|
||||
Toast,
|
||||
IconRefreshLine,
|
||||
VEmpty,
|
||||
VDropdownItem,
|
||||
VTag,
|
||||
} from "@halo-dev/components";
|
||||
import UserEditingModal from "./components/UserEditingModal.vue";
|
||||
import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue";
|
||||
import GrantPermissionModal from "./components/GrantPermissionModal.vue";
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { User, ListedUser } from "@halo-dev/api-client";
|
||||
import type { ListedUser, User } from "@halo-dev/api-client";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
|
@ -232,19 +232,35 @@ onMounted(() => {
|
|||
creationModal.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
function onCreationModalClose() {
|
||||
creationModal.value = false;
|
||||
routeQueryAction.value = undefined;
|
||||
}
|
||||
|
||||
function onEditingModalClose() {
|
||||
editingModal.value = false;
|
||||
selectedUser.value = undefined;
|
||||
}
|
||||
|
||||
function onPasswordChangeModalClose() {
|
||||
passwordChangeModal.value = false;
|
||||
refetch();
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<UserEditingModal v-model:visible="editingModal" :user="selectedUser" />
|
||||
|
||||
<UserCreationModal
|
||||
v-model:visible="creationModal"
|
||||
@close="routeQueryAction = undefined"
|
||||
<UserEditingModal
|
||||
v-if="editingModal && selectedUser"
|
||||
:user="selectedUser"
|
||||
@close="onEditingModalClose"
|
||||
/>
|
||||
|
||||
<UserCreationModal v-if="creationModal" @close="onCreationModalClose" />
|
||||
|
||||
<UserPasswordChangeModal
|
||||
v-model:visible="passwordChangeModal"
|
||||
v-if="passwordChangeModal"
|
||||
:user="selectedUser"
|
||||
@close="refetch"
|
||||
@close="onPasswordChangeModalClose"
|
||||
/>
|
||||
|
||||
<GrantPermissionModal
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { ref, watch } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { CreateUserRequest } from "@halo-dev/api-client";
|
||||
|
||||
|
@ -8,10 +8,6 @@ import type { CreateUserRequest } from "@halo-dev/api-client";
|
|||
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||
|
||||
// libs
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { reset } from "@formkit/core";
|
||||
|
||||
// hooks
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
@ -20,21 +16,12 @@ import { useQueryClient } from "@tanstack/vue-query";
|
|||
const { t } = useI18n();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:visible", visible: boolean): void;
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const initialFormState: CreateUserRequest = {
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
const formState = ref<CreateUserRequest>({
|
||||
avatar: "",
|
||||
bio: "",
|
||||
displayName: "",
|
||||
|
@ -43,38 +30,17 @@ const initialFormState: CreateUserRequest = {
|
|||
password: "",
|
||||
phone: "",
|
||||
roles: [],
|
||||
};
|
||||
|
||||
const formState = ref<CreateUserRequest>(cloneDeep(initialFormState));
|
||||
});
|
||||
const selectedRole = ref("");
|
||||
const saving = ref(false);
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const handleResetForm = () => {
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
reset("user-creation-form");
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
setFocus("creationUserNameInput");
|
||||
} else {
|
||||
handleResetForm();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
setFocus("creationUserNameInput");
|
||||
});
|
||||
|
||||
const handleCreateUser = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
isSubmitting.value = true;
|
||||
|
||||
if (selectedRole.value) {
|
||||
formState.value.roles = [selectedRole.value];
|
||||
|
@ -84,7 +50,7 @@ const handleCreateUser = async () => {
|
|||
createUserRequest: formState.value,
|
||||
});
|
||||
|
||||
onVisibleChange(false);
|
||||
modal.value?.close();
|
||||
|
||||
Toast.success(t("core.common.toast.save_success"));
|
||||
|
||||
|
@ -92,16 +58,16 @@ const handleCreateUser = async () => {
|
|||
} catch (e) {
|
||||
console.error("Failed to create or update user", e);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:title="$t('core.user.editing_modal.titles.create')"
|
||||
:visible="visible"
|
||||
:width="650"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<FormKit
|
||||
id="user-creation-form"
|
||||
|
@ -177,14 +143,13 @@ const handleCreateUser = async () => {
|
|||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
v-if="visible"
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:text="$t('core.common.buttons.submit')"
|
||||
@submit="$formkit.submit('user-creation-form')"
|
||||
>
|
||||
</SubmitButton>
|
||||
<VButton @click="onVisibleChange(false)">
|
||||
<VButton @click="modal?.close()">
|
||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||
</VButton>
|
||||
</VSpace>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { nextTick, ref, watch } from "vue";
|
||||
import { nextTick, ref } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
|
||||
|
@ -10,10 +10,8 @@ import SubmitButton from "@/components/button/SubmitButton.vue";
|
|||
|
||||
// libs
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { reset } from "@formkit/core";
|
||||
|
||||
// hooks
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useQueryClient } from "@tanstack/vue-query";
|
||||
|
@ -23,63 +21,18 @@ const queryClient = useQueryClient();
|
|||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
user?: User;
|
||||
user: User;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
user: undefined,
|
||||
}
|
||||
{}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:visible", visible: boolean): void;
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const initialFormState: User = {
|
||||
spec: {
|
||||
displayName: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
password: "",
|
||||
bio: "",
|
||||
disabled: false,
|
||||
loginHistoryLimit: 0,
|
||||
},
|
||||
apiVersion: "v1alpha1",
|
||||
kind: "User",
|
||||
metadata: {
|
||||
name: "",
|
||||
},
|
||||
};
|
||||
|
||||
const formState = ref<User>(cloneDeep(initialFormState));
|
||||
const saving = ref(false);
|
||||
|
||||
const handleResetForm = () => {
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
reset("user-form");
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
if (props.user) formState.value = cloneDeep(props.user);
|
||||
setFocus("displayNameInput");
|
||||
} else {
|
||||
handleResetForm();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
const formState = ref<User>(cloneDeep(props.user));
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||
|
||||
|
@ -99,14 +52,14 @@ const handleUpdateUser = async () => {
|
|||
};
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
isSubmitting.value = true;
|
||||
|
||||
await apiClient.extension.user.updatev1alpha1User({
|
||||
name: formState.value.metadata.name,
|
||||
user: formState.value,
|
||||
});
|
||||
|
||||
onVisibleChange(false);
|
||||
modal.value?.close();
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["user-detail"] });
|
||||
|
@ -115,16 +68,16 @@ const handleUpdateUser = async () => {
|
|||
} catch (e) {
|
||||
console.error("Failed to create or update user", e);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:title="$t('core.user.editing_modal.titles.update')"
|
||||
:visible="visible"
|
||||
:width="700"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<FormKit
|
||||
id="user-form"
|
||||
|
@ -210,14 +163,13 @@ const handleUpdateUser = async () => {
|
|||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
v-if="visible"
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:text="$t('core.common.buttons.submit')"
|
||||
@submit="$formkit.submit('user-form')"
|
||||
>
|
||||
</SubmitButton>
|
||||
<VButton @click="onVisibleChange(false)">
|
||||
<VButton @click="modal?.close()">
|
||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||
</VButton>
|
||||
</VSpace>
|
||||
|
|
|
@ -1,26 +1,22 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { reset } from "@formkit/core";
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
user?: User;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
user: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:visible", visible: boolean): void;
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
|
@ -34,35 +30,17 @@ const initialFormState: PasswordChangeFormState = {
|
|||
password_confirm: "",
|
||||
};
|
||||
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState));
|
||||
const saving = ref(false);
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
setFocus("passwordInput");
|
||||
} else {
|
||||
handleResetForm();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetForm = () => {
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
reset("password-form");
|
||||
};
|
||||
onMounted(() => {
|
||||
setFocus("passwordInput");
|
||||
});
|
||||
|
||||
const handleChangePassword = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
isSubmitting.value = true;
|
||||
|
||||
const changePasswordRequest = cloneDeep(formState.value);
|
||||
delete changePasswordRequest.password_confirm;
|
||||
|
@ -72,21 +50,21 @@ const handleChangePassword = async () => {
|
|||
changePasswordRequest,
|
||||
});
|
||||
|
||||
onVisibleChange(false);
|
||||
modal.value?.close();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
:visible="visible"
|
||||
ref="modal"
|
||||
:width="500"
|
||||
:title="$t('core.user.change_password_modal.title')"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<FormKit
|
||||
id="password-form"
|
||||
|
@ -122,14 +100,13 @@ const handleChangePassword = async () => {
|
|||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
v-if="visible"
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:text="$t('core.common.buttons.submit')"
|
||||
@submit="$formkit.submit('password-form')"
|
||||
>
|
||||
</SubmitButton>
|
||||
<VButton @click="onVisibleChange(false)">
|
||||
<VButton @click="modal?.close()">
|
||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||
</VButton>
|
||||
</VSpace>
|
||||
|
|
|
@ -4,28 +4,32 @@ import LoginForm from "@/components/login/LoginForm.vue";
|
|||
import { useUserStore } from "@/stores/user";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import SocialAuthProviders from "./SocialAuthProviders.vue";
|
||||
import { ref } from "vue";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
userStore.loginModalVisible = visible;
|
||||
};
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
|
||||
const onLoginSucceed = () => {
|
||||
onVisibleChange(false);
|
||||
modal.value?.close();
|
||||
Toast.success(t("core.login.operations.submit.toast_success"));
|
||||
};
|
||||
|
||||
function onClose() {
|
||||
userStore.loginModalVisible = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
:visible="userStore.loginModalVisible"
|
||||
v-if="userStore.loginModalVisible"
|
||||
ref="modal"
|
||||
:mount-to-body="true"
|
||||
:width="400"
|
||||
:centered="true"
|
||||
:title="$t('core.login.modal.title')"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="onClose"
|
||||
>
|
||||
<LoginForm v-if="userStore.loginModalVisible" @succeed="onLoginSucceed" />
|
||||
<SocialAuthProviders />
|
||||
|
|
|
@ -105,14 +105,19 @@ const tabbarItems = computed(() => {
|
|||
const activeTab = useRouteQuery<string>("tab", tabs.value[0].id, {
|
||||
mode: "push",
|
||||
});
|
||||
|
||||
function onPasswordChangeModalClose() {
|
||||
passwordChangeModal.value = false;
|
||||
refetch();
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<ProfileEditingModal v-model:visible="editingModal" />
|
||||
<ProfileEditingModal v-if="editingModal" @close="editingModal = false" />
|
||||
|
||||
<PasswordChangeModal
|
||||
v-model:visible="passwordChangeModal"
|
||||
v-if="passwordChangeModal"
|
||||
:user="user?.user"
|
||||
@close="refetch"
|
||||
@close="onPasswordChangeModalClose"
|
||||
/>
|
||||
|
||||
<header class="bg-white">
|
||||
|
|
|
@ -1,26 +1,12 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||
import { ref, watch } from "vue";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { reset } from "@formkit/core";
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
user?: User;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
user: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:visible", visible: boolean): void;
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
|
@ -30,41 +16,22 @@ interface PasswordChangeFormState {
|
|||
password_confirm?: string;
|
||||
}
|
||||
|
||||
const initialFormState: PasswordChangeFormState = {
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
|
||||
const formState = ref<PasswordChangeFormState>({
|
||||
oldPassword: "",
|
||||
password: "",
|
||||
password_confirm: "",
|
||||
};
|
||||
});
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState));
|
||||
const saving = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
setFocus("passwordInput");
|
||||
} else {
|
||||
handleResetForm();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetForm = () => {
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
reset("password-form");
|
||||
};
|
||||
onMounted(() => {
|
||||
setFocus("passwordInput");
|
||||
});
|
||||
|
||||
const handleChangePassword = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
isSubmitting.value = true;
|
||||
|
||||
const changeOwnPasswordRequest = cloneDeep(formState.value);
|
||||
delete changeOwnPasswordRequest.password_confirm;
|
||||
|
@ -77,17 +44,17 @@ const handleChangePassword = async () => {
|
|||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
:visible="visible"
|
||||
ref="modal"
|
||||
:width="500"
|
||||
:title="$t('core.uc_profile.change_password_modal.title')"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<FormKit
|
||||
id="password-form"
|
||||
|
@ -135,14 +102,13 @@ const handleChangePassword = async () => {
|
|||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
v-if="visible"
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:text="$t('core.common.buttons.submit')"
|
||||
@submit="$formkit.submit('password-form')"
|
||||
>
|
||||
</SubmitButton>
|
||||
<VButton @click="onVisibleChange(false)">
|
||||
<VButton @click="modal?.close()">
|
||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||
</VButton>
|
||||
</VSpace>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { ref, watch } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
|
||||
|
@ -10,7 +10,6 @@ import SubmitButton from "@/components/button/SubmitButton.vue";
|
|||
|
||||
// libs
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { reset } from "@formkit/core";
|
||||
|
||||
// hooks
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
|
@ -23,74 +22,44 @@ const { t } = useI18n();
|
|||
const queryClient = useQueryClient();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:visible", visible: boolean): void;
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const initialFormState: User = {
|
||||
spec: {
|
||||
displayName: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
password: "",
|
||||
bio: "",
|
||||
disabled: false,
|
||||
loginHistoryLimit: 0,
|
||||
},
|
||||
apiVersion: "v1alpha1",
|
||||
kind: "User",
|
||||
metadata: {
|
||||
name: "",
|
||||
},
|
||||
};
|
||||
|
||||
const formState = ref<User>(cloneDeep(initialFormState));
|
||||
const saving = ref(false);
|
||||
|
||||
const handleResetForm = () => {
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
reset("user-form");
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
if (userStore.currentUser)
|
||||
formState.value = cloneDeep(userStore.currentUser);
|
||||
setFocus("displayNameInput");
|
||||
} else {
|
||||
handleResetForm();
|
||||
}
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
const formState = ref<User>(
|
||||
cloneDeep(userStore.currentUser) || {
|
||||
spec: {
|
||||
displayName: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
password: "",
|
||||
bio: "",
|
||||
disabled: false,
|
||||
loginHistoryLimit: 0,
|
||||
},
|
||||
apiVersion: "v1alpha1",
|
||||
kind: "User",
|
||||
metadata: {
|
||||
name: "",
|
||||
},
|
||||
}
|
||||
);
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
setFocus("displayNameInput");
|
||||
});
|
||||
|
||||
const handleUpdateUser = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
isSubmitting.value = true;
|
||||
|
||||
await apiClient.user.updateCurrentUser({
|
||||
user: formState.value,
|
||||
});
|
||||
|
||||
onVisibleChange(false);
|
||||
modal.value?.close();
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["user-detail"] });
|
||||
|
||||
|
@ -98,7 +67,7 @@ const handleUpdateUser = async () => {
|
|||
} catch (e) {
|
||||
console.error("Failed to update profile", e);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
isSubmitting.value = false;
|
||||
userStore.fetchCurrentUser();
|
||||
}
|
||||
};
|
||||
|
@ -114,10 +83,10 @@ async function onEmailVerifyModalClose() {
|
|||
</script>
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:title="$t('core.uc_profile.editing_modal.title')"
|
||||
:visible="visible"
|
||||
:width="700"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<FormKit
|
||||
id="user-form"
|
||||
|
@ -193,14 +162,13 @@ async function onEmailVerifyModalClose() {
|
|||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
v-if="visible"
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:text="$t('core.common.buttons.submit')"
|
||||
@submit="$formkit.submit('user-form')"
|
||||
>
|
||||
</SubmitButton>
|
||||
<VButton @click="onVisibleChange(false)">
|
||||
<VButton @click="modal?.close()">
|
||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||
</VButton>
|
||||
</VSpace>
|
||||
|
|
Loading…
Reference in New Issue