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() {
|
function handleRouteToUC() {
|
||||||
window.location.href = "/uc";
|
window.location.href = "/uc";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onPasswordChangeModalClose() {
|
||||||
|
passwordChangeModal.value = false;
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<UserEditingModal v-model:visible="editingModal" :user="user?.user" />
|
<UserEditingModal
|
||||||
|
v-if="editingModal && user?.user"
|
||||||
|
:user="user?.user"
|
||||||
|
@close="editingModal = false"
|
||||||
|
/>
|
||||||
|
|
||||||
<UserPasswordChangeModal
|
<UserPasswordChangeModal
|
||||||
v-model:visible="passwordChangeModal"
|
v-if="passwordChangeModal"
|
||||||
:user="user?.user"
|
:user="user?.user"
|
||||||
@close="refetch"
|
@close="onPasswordChangeModalClose"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<header class="bg-white">
|
<header class="bg-white">
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
|
Dialog,
|
||||||
IconAddCircle,
|
IconAddCircle,
|
||||||
|
IconLockPasswordLine,
|
||||||
|
IconRefreshLine,
|
||||||
IconUserFollow,
|
IconUserFollow,
|
||||||
IconUserSettings,
|
IconUserSettings,
|
||||||
IconLockPasswordLine,
|
Toast,
|
||||||
|
VAvatar,
|
||||||
VButton,
|
VButton,
|
||||||
VCard,
|
VCard,
|
||||||
|
VDropdownItem,
|
||||||
|
VEmpty,
|
||||||
|
VEntity,
|
||||||
|
VEntityField,
|
||||||
|
VLoading,
|
||||||
VPageHeader,
|
VPageHeader,
|
||||||
VPagination,
|
VPagination,
|
||||||
VSpace,
|
VSpace,
|
||||||
VTag,
|
|
||||||
VAvatar,
|
|
||||||
VEntity,
|
|
||||||
VEntityField,
|
|
||||||
Dialog,
|
|
||||||
VStatusDot,
|
VStatusDot,
|
||||||
VLoading,
|
VTag,
|
||||||
Toast,
|
|
||||||
IconRefreshLine,
|
|
||||||
VEmpty,
|
|
||||||
VDropdownItem,
|
|
||||||
} from "@halo-dev/components";
|
} from "@halo-dev/components";
|
||||||
import UserEditingModal from "./components/UserEditingModal.vue";
|
import UserEditingModal from "./components/UserEditingModal.vue";
|
||||||
import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue";
|
import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue";
|
||||||
import GrantPermissionModal from "./components/GrantPermissionModal.vue";
|
import GrantPermissionModal from "./components/GrantPermissionModal.vue";
|
||||||
import { computed, onMounted, ref, watch } from "vue";
|
import { computed, onMounted, ref, watch } from "vue";
|
||||||
import { apiClient } from "@/utils/api-client";
|
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 { rbacAnnotations } from "@/constants/annotations";
|
||||||
import { formatDatetime } from "@/utils/date";
|
import { formatDatetime } from "@/utils/date";
|
||||||
import { useRouteQuery } from "@vueuse/router";
|
import { useRouteQuery } from "@vueuse/router";
|
||||||
|
@ -232,19 +232,35 @@ onMounted(() => {
|
||||||
creationModal.value = true;
|
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>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<UserEditingModal v-model:visible="editingModal" :user="selectedUser" />
|
<UserEditingModal
|
||||||
|
v-if="editingModal && selectedUser"
|
||||||
<UserCreationModal
|
:user="selectedUser"
|
||||||
v-model:visible="creationModal"
|
@close="onEditingModalClose"
|
||||||
@close="routeQueryAction = undefined"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<UserCreationModal v-if="creationModal" @close="onCreationModalClose" />
|
||||||
|
|
||||||
<UserPasswordChangeModal
|
<UserPasswordChangeModal
|
||||||
v-model:visible="passwordChangeModal"
|
v-if="passwordChangeModal"
|
||||||
:user="selectedUser"
|
:user="selectedUser"
|
||||||
@close="refetch"
|
@close="onPasswordChangeModalClose"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<GrantPermissionModal
|
<GrantPermissionModal
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { ref, watch } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import type { CreateUserRequest } from "@halo-dev/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 { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||||
|
|
||||||
// libs
|
|
||||||
import { cloneDeep } from "lodash-es";
|
|
||||||
import { reset } from "@formkit/core";
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
import { setFocus } from "@/formkit/utils/focus";
|
import { setFocus } from "@/formkit/utils/focus";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
@ -20,21 +16,12 @@ import { useQueryClient } from "@tanstack/vue-query";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
visible: boolean;
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
visible: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: "update:visible", visible: boolean): void;
|
|
||||||
(event: "close"): void;
|
(event: "close"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const initialFormState: CreateUserRequest = {
|
const modal = ref<InstanceType<typeof VModal>>();
|
||||||
|
const formState = ref<CreateUserRequest>({
|
||||||
avatar: "",
|
avatar: "",
|
||||||
bio: "",
|
bio: "",
|
||||||
displayName: "",
|
displayName: "",
|
||||||
|
@ -43,38 +30,17 @@ const initialFormState: CreateUserRequest = {
|
||||||
password: "",
|
password: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
roles: [],
|
roles: [],
|
||||||
};
|
});
|
||||||
|
|
||||||
const formState = ref<CreateUserRequest>(cloneDeep(initialFormState));
|
|
||||||
const selectedRole = ref("");
|
const selectedRole = ref("");
|
||||||
const saving = ref(false);
|
const isSubmitting = ref(false);
|
||||||
|
|
||||||
const handleResetForm = () => {
|
onMounted(() => {
|
||||||
formState.value = cloneDeep(initialFormState);
|
setFocus("creationUserNameInput");
|
||||||
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");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreateUser = async () => {
|
const handleCreateUser = async () => {
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
isSubmitting.value = true;
|
||||||
|
|
||||||
if (selectedRole.value) {
|
if (selectedRole.value) {
|
||||||
formState.value.roles = [selectedRole.value];
|
formState.value.roles = [selectedRole.value];
|
||||||
|
@ -84,7 +50,7 @@ const handleCreateUser = async () => {
|
||||||
createUserRequest: formState.value,
|
createUserRequest: formState.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
onVisibleChange(false);
|
modal.value?.close();
|
||||||
|
|
||||||
Toast.success(t("core.common.toast.save_success"));
|
Toast.success(t("core.common.toast.save_success"));
|
||||||
|
|
||||||
|
@ -92,16 +58,16 @@ const handleCreateUser = async () => {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to create or update user", e);
|
console.error("Failed to create or update user", e);
|
||||||
} finally {
|
} finally {
|
||||||
saving.value = false;
|
isSubmitting.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
|
ref="modal"
|
||||||
:title="$t('core.user.editing_modal.titles.create')"
|
:title="$t('core.user.editing_modal.titles.create')"
|
||||||
:visible="visible"
|
|
||||||
:width="650"
|
:width="650"
|
||||||
@update:visible="onVisibleChange"
|
@close="emit('close')"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
id="user-creation-form"
|
id="user-creation-form"
|
||||||
|
@ -177,14 +143,13 @@ const handleCreateUser = async () => {
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
v-if="visible"
|
:loading="isSubmitting"
|
||||||
:loading="saving"
|
|
||||||
type="secondary"
|
type="secondary"
|
||||||
:text="$t('core.common.buttons.submit')"
|
:text="$t('core.common.buttons.submit')"
|
||||||
@submit="$formkit.submit('user-creation-form')"
|
@submit="$formkit.submit('user-creation-form')"
|
||||||
>
|
>
|
||||||
</SubmitButton>
|
</SubmitButton>
|
||||||
<VButton @click="onVisibleChange(false)">
|
<VButton @click="modal?.close()">
|
||||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||||
</VButton>
|
</VButton>
|
||||||
</VSpace>
|
</VSpace>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { nextTick, ref, watch } from "vue";
|
import { nextTick, ref } from "vue";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import type { User } from "@halo-dev/api-client";
|
import type { User } from "@halo-dev/api-client";
|
||||||
|
|
||||||
|
@ -10,10 +10,8 @@ import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||||
|
|
||||||
// libs
|
// libs
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
import { reset } from "@formkit/core";
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
import { setFocus } from "@/formkit/utils/focus";
|
|
||||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useQueryClient } from "@tanstack/vue-query";
|
import { useQueryClient } from "@tanstack/vue-query";
|
||||||
|
@ -23,63 +21,18 @@ const queryClient = useQueryClient();
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
visible: boolean;
|
user: User;
|
||||||
user?: User;
|
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{}
|
||||||
visible: false,
|
|
||||||
user: undefined,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: "update:visible", visible: boolean): void;
|
|
||||||
(event: "close"): void;
|
(event: "close"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const initialFormState: User = {
|
const modal = ref<InstanceType<typeof VModal>>();
|
||||||
spec: {
|
const formState = ref<User>(cloneDeep(props.user));
|
||||||
displayName: "",
|
const isSubmitting = ref(false);
|
||||||
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 annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||||
|
|
||||||
|
@ -99,14 +52,14 @@ const handleUpdateUser = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
isSubmitting.value = true;
|
||||||
|
|
||||||
await apiClient.extension.user.updatev1alpha1User({
|
await apiClient.extension.user.updatev1alpha1User({
|
||||||
name: formState.value.metadata.name,
|
name: formState.value.metadata.name,
|
||||||
user: formState.value,
|
user: formState.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
onVisibleChange(false);
|
modal.value?.close();
|
||||||
|
|
||||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["user-detail"] });
|
queryClient.invalidateQueries({ queryKey: ["user-detail"] });
|
||||||
|
@ -115,16 +68,16 @@ const handleUpdateUser = async () => {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to create or update user", e);
|
console.error("Failed to create or update user", e);
|
||||||
} finally {
|
} finally {
|
||||||
saving.value = false;
|
isSubmitting.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
|
ref="modal"
|
||||||
:title="$t('core.user.editing_modal.titles.update')"
|
:title="$t('core.user.editing_modal.titles.update')"
|
||||||
:visible="visible"
|
|
||||||
:width="700"
|
:width="700"
|
||||||
@update:visible="onVisibleChange"
|
@close="emit('close')"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
id="user-form"
|
id="user-form"
|
||||||
|
@ -210,14 +163,13 @@ const handleUpdateUser = async () => {
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
v-if="visible"
|
:loading="isSubmitting"
|
||||||
:loading="saving"
|
|
||||||
type="secondary"
|
type="secondary"
|
||||||
:text="$t('core.common.buttons.submit')"
|
:text="$t('core.common.buttons.submit')"
|
||||||
@submit="$formkit.submit('user-form')"
|
@submit="$formkit.submit('user-form')"
|
||||||
>
|
>
|
||||||
</SubmitButton>
|
</SubmitButton>
|
||||||
<VButton @click="onVisibleChange(false)">
|
<VButton @click="modal?.close()">
|
||||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||||
</VButton>
|
</VButton>
|
||||||
</VSpace>
|
</VSpace>
|
||||||
|
|
|
@ -1,26 +1,22 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
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 type { User } from "@halo-dev/api-client";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
import { reset } from "@formkit/core";
|
|
||||||
import { setFocus } from "@/formkit/utils/focus";
|
import { setFocus } from "@/formkit/utils/focus";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
visible: boolean;
|
|
||||||
user?: User;
|
user?: User;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
visible: false,
|
|
||||||
user: undefined,
|
user: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: "update:visible", visible: boolean): void;
|
|
||||||
(event: "close"): void;
|
(event: "close"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -34,35 +30,17 @@ const initialFormState: PasswordChangeFormState = {
|
||||||
password_confirm: "",
|
password_confirm: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const modal = ref<InstanceType<typeof VModal>>();
|
||||||
const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState));
|
const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState));
|
||||||
const saving = ref(false);
|
const isSubmitting = ref(false);
|
||||||
|
|
||||||
watch(
|
onMounted(() => {
|
||||||
() => props.visible,
|
setFocus("passwordInput");
|
||||||
(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");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangePassword = async () => {
|
const handleChangePassword = async () => {
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
isSubmitting.value = true;
|
||||||
|
|
||||||
const changePasswordRequest = cloneDeep(formState.value);
|
const changePasswordRequest = cloneDeep(formState.value);
|
||||||
delete changePasswordRequest.password_confirm;
|
delete changePasswordRequest.password_confirm;
|
||||||
|
@ -72,21 +50,21 @@ const handleChangePassword = async () => {
|
||||||
changePasswordRequest,
|
changePasswordRequest,
|
||||||
});
|
});
|
||||||
|
|
||||||
onVisibleChange(false);
|
modal.value?.close();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
saving.value = false;
|
isSubmitting.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
:visible="visible"
|
ref="modal"
|
||||||
:width="500"
|
:width="500"
|
||||||
:title="$t('core.user.change_password_modal.title')"
|
:title="$t('core.user.change_password_modal.title')"
|
||||||
@update:visible="onVisibleChange"
|
@close="emit('close')"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
id="password-form"
|
id="password-form"
|
||||||
|
@ -122,14 +100,13 @@ const handleChangePassword = async () => {
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
v-if="visible"
|
:loading="isSubmitting"
|
||||||
:loading="saving"
|
|
||||||
type="secondary"
|
type="secondary"
|
||||||
:text="$t('core.common.buttons.submit')"
|
:text="$t('core.common.buttons.submit')"
|
||||||
@submit="$formkit.submit('password-form')"
|
@submit="$formkit.submit('password-form')"
|
||||||
>
|
>
|
||||||
</SubmitButton>
|
</SubmitButton>
|
||||||
<VButton @click="onVisibleChange(false)">
|
<VButton @click="modal?.close()">
|
||||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||||
</VButton>
|
</VButton>
|
||||||
</VSpace>
|
</VSpace>
|
||||||
|
|
|
@ -4,28 +4,32 @@ import LoginForm from "@/components/login/LoginForm.vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import SocialAuthProviders from "./SocialAuthProviders.vue";
|
import SocialAuthProviders from "./SocialAuthProviders.vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const onVisibleChange = (visible: boolean) => {
|
const modal = ref<InstanceType<typeof VModal>>();
|
||||||
userStore.loginModalVisible = visible;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onLoginSucceed = () => {
|
const onLoginSucceed = () => {
|
||||||
onVisibleChange(false);
|
modal.value?.close();
|
||||||
Toast.success(t("core.login.operations.submit.toast_success"));
|
Toast.success(t("core.login.operations.submit.toast_success"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
userStore.loginModalVisible = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
:visible="userStore.loginModalVisible"
|
v-if="userStore.loginModalVisible"
|
||||||
|
ref="modal"
|
||||||
:mount-to-body="true"
|
:mount-to-body="true"
|
||||||
:width="400"
|
:width="400"
|
||||||
:centered="true"
|
:centered="true"
|
||||||
:title="$t('core.login.modal.title')"
|
:title="$t('core.login.modal.title')"
|
||||||
@update:visible="onVisibleChange"
|
@close="onClose"
|
||||||
>
|
>
|
||||||
<LoginForm v-if="userStore.loginModalVisible" @succeed="onLoginSucceed" />
|
<LoginForm v-if="userStore.loginModalVisible" @succeed="onLoginSucceed" />
|
||||||
<SocialAuthProviders />
|
<SocialAuthProviders />
|
||||||
|
|
|
@ -105,14 +105,19 @@ const tabbarItems = computed(() => {
|
||||||
const activeTab = useRouteQuery<string>("tab", tabs.value[0].id, {
|
const activeTab = useRouteQuery<string>("tab", tabs.value[0].id, {
|
||||||
mode: "push",
|
mode: "push",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function onPasswordChangeModalClose() {
|
||||||
|
passwordChangeModal.value = false;
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<ProfileEditingModal v-model:visible="editingModal" />
|
<ProfileEditingModal v-if="editingModal" @close="editingModal = false" />
|
||||||
|
|
||||||
<PasswordChangeModal
|
<PasswordChangeModal
|
||||||
v-model:visible="passwordChangeModal"
|
v-if="passwordChangeModal"
|
||||||
:user="user?.user"
|
:user="user?.user"
|
||||||
@close="refetch"
|
@close="onPasswordChangeModalClose"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<header class="bg-white">
|
<header class="bg-white">
|
||||||
|
|
|
@ -1,26 +1,12 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
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 { apiClient } from "@/utils/api-client";
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
import { reset } from "@formkit/core";
|
|
||||||
import { setFocus } from "@/formkit/utils/focus";
|
import { setFocus } from "@/formkit/utils/focus";
|
||||||
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
visible: boolean;
|
|
||||||
user?: User;
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
visible: false,
|
|
||||||
user: undefined,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: "update:visible", visible: boolean): void;
|
|
||||||
(event: "close"): void;
|
(event: "close"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -30,41 +16,22 @@ interface PasswordChangeFormState {
|
||||||
password_confirm?: string;
|
password_confirm?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialFormState: PasswordChangeFormState = {
|
const modal = ref<InstanceType<typeof VModal>>();
|
||||||
|
|
||||||
|
const formState = ref<PasswordChangeFormState>({
|
||||||
oldPassword: "",
|
oldPassword: "",
|
||||||
password: "",
|
password: "",
|
||||||
password_confirm: "",
|
password_confirm: "",
|
||||||
};
|
});
|
||||||
|
const isSubmitting = ref(false);
|
||||||
|
|
||||||
const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState));
|
onMounted(() => {
|
||||||
const saving = ref(false);
|
setFocus("passwordInput");
|
||||||
|
});
|
||||||
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");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangePassword = async () => {
|
const handleChangePassword = async () => {
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
isSubmitting.value = true;
|
||||||
|
|
||||||
const changeOwnPasswordRequest = cloneDeep(formState.value);
|
const changeOwnPasswordRequest = cloneDeep(formState.value);
|
||||||
delete changeOwnPasswordRequest.password_confirm;
|
delete changeOwnPasswordRequest.password_confirm;
|
||||||
|
@ -77,17 +44,17 @@ const handleChangePassword = async () => {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
saving.value = false;
|
isSubmitting.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
:visible="visible"
|
ref="modal"
|
||||||
:width="500"
|
:width="500"
|
||||||
:title="$t('core.uc_profile.change_password_modal.title')"
|
:title="$t('core.uc_profile.change_password_modal.title')"
|
||||||
@update:visible="onVisibleChange"
|
@close="emit('close')"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
id="password-form"
|
id="password-form"
|
||||||
|
@ -135,14 +102,13 @@ const handleChangePassword = async () => {
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
v-if="visible"
|
:loading="isSubmitting"
|
||||||
:loading="saving"
|
|
||||||
type="secondary"
|
type="secondary"
|
||||||
:text="$t('core.common.buttons.submit')"
|
:text="$t('core.common.buttons.submit')"
|
||||||
@submit="$formkit.submit('password-form')"
|
@submit="$formkit.submit('password-form')"
|
||||||
>
|
>
|
||||||
</SubmitButton>
|
</SubmitButton>
|
||||||
<VButton @click="onVisibleChange(false)">
|
<VButton @click="modal?.close()">
|
||||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||||
</VButton>
|
</VButton>
|
||||||
</VSpace>
|
</VSpace>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { ref, watch } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import type { User } from "@halo-dev/api-client";
|
import type { User } from "@halo-dev/api-client";
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||||
|
|
||||||
// libs
|
// libs
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
import { reset } from "@formkit/core";
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
import { setFocus } from "@/formkit/utils/focus";
|
import { setFocus } from "@/formkit/utils/focus";
|
||||||
|
@ -23,74 +22,44 @@ const { t } = useI18n();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
visible: boolean;
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
visible: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: "update:visible", visible: boolean): void;
|
|
||||||
(event: "close"): void;
|
(event: "close"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const initialFormState: User = {
|
const modal = ref<InstanceType<typeof VModal>>();
|
||||||
spec: {
|
const formState = ref<User>(
|
||||||
displayName: "",
|
cloneDeep(userStore.currentUser) || {
|
||||||
email: "",
|
spec: {
|
||||||
phone: "",
|
displayName: "",
|
||||||
password: "",
|
email: "",
|
||||||
bio: "",
|
phone: "",
|
||||||
disabled: false,
|
password: "",
|
||||||
loginHistoryLimit: 0,
|
bio: "",
|
||||||
},
|
disabled: false,
|
||||||
apiVersion: "v1alpha1",
|
loginHistoryLimit: 0,
|
||||||
kind: "User",
|
},
|
||||||
metadata: {
|
apiVersion: "v1alpha1",
|
||||||
name: "",
|
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 isSubmitting = ref(false);
|
||||||
|
|
||||||
const onVisibleChange = (visible: boolean) => {
|
onMounted(() => {
|
||||||
emit("update:visible", visible);
|
setFocus("displayNameInput");
|
||||||
if (!visible) {
|
});
|
||||||
emit("close");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateUser = async () => {
|
const handleUpdateUser = async () => {
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
isSubmitting.value = true;
|
||||||
|
|
||||||
await apiClient.user.updateCurrentUser({
|
await apiClient.user.updateCurrentUser({
|
||||||
user: formState.value,
|
user: formState.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
onVisibleChange(false);
|
modal.value?.close();
|
||||||
|
|
||||||
queryClient.invalidateQueries({ queryKey: ["user-detail"] });
|
queryClient.invalidateQueries({ queryKey: ["user-detail"] });
|
||||||
|
|
||||||
|
@ -98,7 +67,7 @@ const handleUpdateUser = async () => {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to update profile", e);
|
console.error("Failed to update profile", e);
|
||||||
} finally {
|
} finally {
|
||||||
saving.value = false;
|
isSubmitting.value = false;
|
||||||
userStore.fetchCurrentUser();
|
userStore.fetchCurrentUser();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -114,10 +83,10 @@ async function onEmailVerifyModalClose() {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
|
ref="modal"
|
||||||
:title="$t('core.uc_profile.editing_modal.title')"
|
:title="$t('core.uc_profile.editing_modal.title')"
|
||||||
:visible="visible"
|
|
||||||
:width="700"
|
:width="700"
|
||||||
@update:visible="onVisibleChange"
|
@close="emit('close')"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
id="user-form"
|
id="user-form"
|
||||||
|
@ -193,14 +162,13 @@ async function onEmailVerifyModalClose() {
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
v-if="visible"
|
:loading="isSubmitting"
|
||||||
:loading="saving"
|
|
||||||
type="secondary"
|
type="secondary"
|
||||||
:text="$t('core.common.buttons.submit')"
|
:text="$t('core.common.buttons.submit')"
|
||||||
@submit="$formkit.submit('user-form')"
|
@submit="$formkit.submit('user-form')"
|
||||||
>
|
>
|
||||||
</SubmitButton>
|
</SubmitButton>
|
||||||
<VButton @click="onVisibleChange(false)">
|
<VButton @click="modal?.close()">
|
||||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||||
</VButton>
|
</VButton>
|
||||||
</VSpace>
|
</VSpace>
|
||||||
|
|
Loading…
Reference in New Issue